-diff -Naur backports-4.2.6-1.org/drivers/net/usb/asix_common.c backports-4.2.6-1/drivers/net/usb/asix_common.c
---- backports-4.2.6-1.org/drivers/net/usb/asix_common.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/asix_common.c 2016-06-28 14:35:17.965307221 +0200
-@@ -0,0 +1,584 @@
-+/*
-+ * ASIX AX8817X based USB 2.0 Ethernet Devices
-+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
-+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
-+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
-+ * Copyright (c) 2002-2003 TiVo Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "asix.h"
-+
-+int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ int ret;
-+ ret = usbnet_read_cmd(dev, cmd,
-+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, index, data, size);
-+
-+ if (ret != size && ret >= 0)
-+ return -EINVAL;
-+ return ret;
-+}
-+
-+int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ return usbnet_write_cmd(dev, cmd,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, index, data, size);
-+}
-+
-+void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ usbnet_write_cmd_async(dev, cmd,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, index, data, size);
-+}
-+
-+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
-+ struct asix_rx_fixup_info *rx)
-+{
-+ int offset = 0;
-+
-+ while (offset + sizeof(u16) <= skb->len) {
-+ u16 remaining = 0;
-+ unsigned char *data;
-+
-+ if (!rx->size) {
-+ if ((skb->len - offset == sizeof(u16)) ||
-+ rx->split_head) {
-+ if(!rx->split_head) {
-+ rx->header = get_unaligned_le16(
-+ skb->data + offset);
-+ rx->split_head = true;
-+ offset += sizeof(u16);
-+ break;
-+ } else {
-+ rx->header |= (get_unaligned_le16(
-+ skb->data + offset)
-+ << 16);
-+ rx->split_head = false;
-+ offset += sizeof(u16);
-+ }
-+ } else {
-+ rx->header = get_unaligned_le32(skb->data +
-+ offset);
-+ offset += sizeof(u32);
-+ }
-+
-+ /* get the packet length */
-+ rx->size = (u16) (rx->header & 0x7ff);
-+ if (rx->size != ((~rx->header >> 16) & 0x7ff)) {
-+ netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
-+ rx->header, offset);
-+ rx->size = 0;
-+ return 0;
-+ }
-+ rx->ax_skb = netdev_alloc_skb_ip_align(dev->net,
-+ rx->size);
-+ if (!rx->ax_skb)
-+ return 0;
-+ }
-+
-+ if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
-+ netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
-+ rx->size);
-+ kfree_skb(rx->ax_skb);
-+ rx->ax_skb = NULL;
-+ rx->size = 0U;
-+
-+ return 0;
-+ }
-+
-+ if (rx->size > skb->len - offset) {
-+ remaining = rx->size - (skb->len - offset);
-+ rx->size = skb->len - offset;
-+ }
-+
-+ data = skb_put(rx->ax_skb, rx->size);
-+ memcpy(data, skb->data + offset, rx->size);
-+ if (!remaining)
-+ usbnet_skb_return(dev, rx->ax_skb);
-+
-+ offset += (rx->size + 1) & 0xfffe;
-+ rx->size = remaining;
-+ }
-+
-+ if (skb->len != offset) {
-+ netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
-+ skb->len, offset);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct asix_common_private *dp = dev->driver_priv;
-+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
-+
-+ return asix_rx_fixup_internal(dev, skb, rx);
-+}
-+
-+struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ int padlen;
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+ u32 packet_len;
-+ u32 padbytes = 0xffff0000;
-+
-+ padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4;
-+
-+ /* We need to push 4 bytes in front of frame (packet_len)
-+ * and maybe add 4 bytes after the end (if padlen is 4)
-+ *
-+ * Avoid skb_copy_expand() expensive call, using following rules :
-+ * - We are allowed to push 4 bytes in headroom if skb_header_cloned()
-+ * is false (and if we have 4 bytes of headroom)
-+ * - We are allowed to put 4 bytes at tail if skb_cloned()
-+ * is false (and if we have 4 bytes of tailroom)
-+ *
-+ * TCP packets for example are cloned, but skb_header_release()
-+ * was called in tcp stack, allowing us to use headroom for our needs.
-+ */
-+ if (!skb_header_cloned(skb) &&
-+ !(padlen && skb_cloned(skb)) &&
-+ headroom + tailroom >= 4 + padlen) {
-+ /* following should not happen, but better be safe */
-+ if (headroom < 4 ||
-+ tailroom < padlen) {
-+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ }
-+ } else {
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&packet_len);
-+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
-+
-+ if (padlen) {
-+ cpu_to_le32s(&padbytes);
-+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
-+ skb_put(skb, sizeof(padbytes));
-+ }
-+
-+ usbnet_set_skb_tx_stats(skb, 1, 0);
-+ return skb;
-+}
-+
-+int asix_set_sw_mii(struct usbnet *dev)
-+{
-+ int ret;
-+ ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to enable software MII access\n");
-+ return ret;
-+}
-+
-+int asix_set_hw_mii(struct usbnet *dev)
-+{
-+ int ret;
-+ ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to enable hardware MII access\n");
-+ return ret;
-+}
-+
-+int asix_read_phy_addr(struct usbnet *dev, int internal)
-+{
-+ int offset = (internal ? 1 : 0);
-+ u8 buf[2];
-+ int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
-+
-+ netdev_dbg(dev->net, "asix_get_phy_addr()\n");
-+
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
-+ goto out;
-+ }
-+ netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
-+ *((__le16 *)buf));
-+ ret = buf[offset];
-+
-+out:
-+ return ret;
-+}
-+
-+int asix_get_phy_addr(struct usbnet *dev)
-+{
-+ /* return the address of the internal phy */
-+ return asix_read_phy_addr(dev, 1);
-+}
-+
-+
-+int asix_sw_reset(struct usbnet *dev, u8 flags)
-+{
-+ int ret;
-+
-+ ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
-+
-+ return ret;
-+}
-+
-+u16 asix_read_rx_ctl(struct usbnet *dev)
-+{
-+ __le16 v;
-+ int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
-+
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
-+ goto out;
-+ }
-+ ret = le16_to_cpu(v);
-+out:
-+ return ret;
-+}
-+
-+int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
-+ mode, ret);
-+
-+ return ret;
-+}
-+
-+u16 asix_read_medium_status(struct usbnet *dev)
-+{
-+ __le16 v;
-+ int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
-+
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
-+ ret);
-+ return ret; /* TODO: callers not checking for error ret */
-+ }
-+
-+ return le16_to_cpu(v);
-+
-+}
-+
-+int asix_write_medium_mode(struct usbnet *dev, u16 mode)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
-+ mode, ret);
-+
-+ return ret;
-+}
-+
-+int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
-+ value, ret);
-+
-+ if (sleep)
-+ msleep(sleep);
-+
-+ return ret;
-+}
-+
-+/*
-+ * AX88772 & AX88178 have a 16-bit RX_CTL value
-+ */
-+void asix_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ u16 rx_ctl = AX_DEFAULT_RX_CTL;
-+
-+ if (net->flags & IFF_PROMISC) {
-+ rx_ctl |= AX_RX_CTL_PRO;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > AX_MAX_MCAST) {
-+ rx_ctl |= AX_RX_CTL_AMALL;
-+ } else if (netdev_mc_empty(net)) {
-+ /* just broadcast and directed */
-+ } else {
-+ /* We use the 20 byte dev->data
-+ * for our 8 byte filter buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later */
-+ struct netdev_hw_addr *ha;
-+ u32 crc_bits;
-+
-+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
-+
-+ /* Build the multicast hash filter. */
-+ netdev_for_each_mc_addr(ha, net) {
-+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ data->multi_filter[crc_bits >> 3] |=
-+ 1 << (crc_bits & 7);
-+ }
-+
-+ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
-+ AX_MCAST_FILTER_SIZE, data->multi_filter);
-+
-+ rx_ctl |= AX_RX_CTL_AM;
-+ }
-+
-+ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
-+}
-+
-+int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 res;
-+
-+ mutex_lock(&dev->phy_mutex);
-+ asix_set_sw_mii(dev);
-+ asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
-+ (__u16)loc, 2, &res);
-+ asix_set_hw_mii(dev);
-+ mutex_unlock(&dev->phy_mutex);
-+
-+ netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
-+ phy_id, loc, le16_to_cpu(res));
-+
-+ return le16_to_cpu(res);
-+}
-+
-+void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 res = cpu_to_le16(val);
-+
-+ netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
-+ phy_id, loc, val);
-+ mutex_lock(&dev->phy_mutex);
-+ asix_set_sw_mii(dev);
-+ asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
-+ asix_set_hw_mii(dev);
-+ mutex_unlock(&dev->phy_mutex);
-+}
-+
-+void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt;
-+
-+ if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
-+ wolinfo->supported = 0;
-+ wolinfo->wolopts = 0;
-+ return;
-+ }
-+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
-+ wolinfo->wolopts = 0;
-+ if (opt & AX_MONITOR_LINK)
-+ wolinfo->wolopts |= WAKE_PHY;
-+ if (opt & AX_MONITOR_MAGIC)
-+ wolinfo->wolopts |= WAKE_MAGIC;
-+}
-+
-+int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt = 0;
-+
-+ if (wolinfo->wolopts & WAKE_PHY)
-+ opt |= AX_MONITOR_LINK;
-+ if (wolinfo->wolopts & WAKE_MAGIC)
-+ opt |= AX_MONITOR_MAGIC;
-+
-+ if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
-+ opt, 0, 0, NULL) < 0)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+int asix_get_eeprom_len(struct net_device *net)
-+{
-+ return AX_EEPROM_LEN;
-+}
-+
-+int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
-+ u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u16 *eeprom_buff;
-+ int first_word, last_word;
-+ int i;
-+
-+ if (eeprom->len == 0)
-+ return -EINVAL;
-+
-+ eeprom->magic = AX_EEPROM_MAGIC;
-+
-+ first_word = eeprom->offset >> 1;
-+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
-+
-+ eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
-+ GFP_KERNEL);
-+ if (!eeprom_buff)
-+ return -ENOMEM;
-+
-+ /* ax8817x returns 2 bytes from eeprom on read */
-+ for (i = first_word; i <= last_word; i++) {
-+ if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
-+ &(eeprom_buff[i - first_word])) < 0) {
-+ kfree(eeprom_buff);
-+ return -EIO;
-+ }
-+ }
-+
-+ memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
-+ kfree(eeprom_buff);
-+ return 0;
-+}
-+
-+int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
-+ u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u16 *eeprom_buff;
-+ int first_word, last_word;
-+ int i;
-+ int ret;
-+
-+ netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n",
-+ eeprom->len, eeprom->offset, eeprom->magic);
-+
-+ if (eeprom->len == 0)
-+ return -EINVAL;
-+
-+ if (eeprom->magic != AX_EEPROM_MAGIC)
-+ return -EINVAL;
-+
-+ first_word = eeprom->offset >> 1;
-+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
-+
-+ eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
-+ GFP_KERNEL);
-+ if (!eeprom_buff)
-+ return -ENOMEM;
-+
-+ /* align data to 16 bit boundaries, read the missing data from
-+ the EEPROM */
-+ if (eeprom->offset & 1) {
-+ ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
-+ &(eeprom_buff[0]));
-+ if (ret < 0) {
-+ netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
-+ goto free;
-+ }
-+ }
-+
-+ if ((eeprom->offset + eeprom->len) & 1) {
-+ ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
-+ &(eeprom_buff[last_word - first_word]));
-+ if (ret < 0) {
-+ netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
-+ goto free;
-+ }
-+ }
-+
-+ memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);
-+
-+ /* write data to EEPROM */
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(net, "Failed to enable EEPROM write\n");
-+ goto free;
-+ }
-+ msleep(20);
-+
-+ for (i = first_word; i <= last_word; i++) {
-+ netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
-+ i, eeprom_buff[i - first_word]);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
-+ eeprom_buff[i - first_word], 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
-+ i);
-+ goto free;
-+ }
-+ msleep(20);
-+ }
-+
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(net, "Failed to disable EEPROM write\n");
-+ goto free;
-+ }
-+
-+ ret = 0;
-+free:
-+ kfree(eeprom_buff);
-+ return ret;
-+}
-+
-+void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
-+{
-+ /* Inherit standard device info */
-+ usbnet_get_drvinfo(net, info);
-+ strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
-+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
-+ info->eedump_len = AX_EEPROM_LEN;
-+}
-+
-+int asix_set_mac_address(struct net_device *net, void *p)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ struct sockaddr *addr = p;
-+
-+ if (netif_running(net))
-+ return -EBUSY;
-+ if (!is_valid_ether_addr(addr->sa_data))
-+ return -EADDRNOTAVAIL;
-+
-+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
-+
-+ /* We use the 20 byte dev->data
-+ * for our 6 byte mac buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later */
-+ memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
-+ asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+
-+ return 0;
-+}
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/asix_devices.c backports-4.2.6-1/drivers/net/usb/asix_devices.c
---- backports-4.2.6-1.org/drivers/net/usb/asix_devices.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/asix_devices.c 2016-06-28 14:35:17.965307221 +0200
-@@ -0,0 +1,1107 @@
-+/*
-+ * ASIX AX8817X based USB 2.0 Ethernet Devices
-+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
-+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
-+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
-+ * Copyright (c) 2002-2003 TiVo Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "asix.h"
-+
-+#define PHY_MODE_MARVELL 0x0000
-+#define MII_MARVELL_LED_CTRL 0x0018
-+#define MII_MARVELL_STATUS 0x001b
-+#define MII_MARVELL_CTRL 0x0014
-+
-+#define MARVELL_LED_MANUAL 0x0019
-+
-+#define MARVELL_STATUS_HWCFG 0x0004
-+
-+#define MARVELL_CTRL_TXDELAY 0x0002
-+#define MARVELL_CTRL_RXDELAY 0x0080
-+
-+#define PHY_MODE_RTL8211CL 0x000C
-+
-+struct ax88172_int_data {
-+ __le16 res1;
-+ u8 link;
-+ __le16 res2;
-+ u8 status;
-+ __le16 res3;
-+} __packed;
-+
-+static void asix_status(struct usbnet *dev, struct urb *urb)
-+{
-+ struct ax88172_int_data *event;
-+ int link;
-+
-+ if (urb->actual_length < 8)
-+ return;
-+
-+ event = urb->transfer_buffer;
-+ link = event->link & 0x01;
-+ if (netif_carrier_ok(dev->net) != link) {
-+ usbnet_link_change(dev, link, 1);
-+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
-+ }
-+}
-+
-+static void asix_set_netdev_dev_addr(struct usbnet *dev, u8 *addr)
-+{
-+ if (is_valid_ether_addr(addr)) {
-+ memcpy(dev->net->dev_addr, addr, ETH_ALEN);
-+ } else {
-+ netdev_info(dev->net, "invalid hw address, using random\n");
-+ eth_hw_addr_random(dev->net);
-+ }
-+}
-+
-+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
-+static u32 asix_get_phyid(struct usbnet *dev)
-+{
-+ int phy_reg;
-+ u32 phy_id;
-+ int i;
-+
-+ /* Poll for the rare case the FW or phy isn't ready yet. */
-+ for (i = 0; i < 100; i++) {
-+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
-+ if (phy_reg != 0 && phy_reg != 0xFFFF)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ if (phy_reg <= 0 || phy_reg == 0xFFFF)
-+ return 0;
-+
-+ phy_id = (phy_reg & 0xffff) << 16;
-+
-+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
-+ if (phy_reg < 0)
-+ return 0;
-+
-+ phy_id |= (phy_reg & 0xffff);
-+
-+ return phy_id;
-+}
-+
-+static u32 asix_get_link(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return mii_link_ok(&dev->mii);
-+}
-+
-+static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+/* We need to override some ethtool_ops so we require our
-+ own structure so we don't interfere with other usbnet
-+ devices that may be connected at the same time. */
-+static const struct ethtool_ops ax88172_ethtool_ops = {
-+ .get_drvinfo = asix_get_drvinfo,
-+ .get_link = asix_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = asix_get_wol,
-+ .set_wol = asix_set_wol,
-+ .get_eeprom_len = asix_get_eeprom_len,
-+ .get_eeprom = asix_get_eeprom,
-+ .set_eeprom = asix_set_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static void ax88172_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ u8 rx_ctl = 0x8c;
-+
-+ if (net->flags & IFF_PROMISC) {
-+ rx_ctl |= 0x01;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > AX_MAX_MCAST) {
-+ rx_ctl |= 0x02;
-+ } else if (netdev_mc_empty(net)) {
-+ /* just broadcast and directed */
-+ } else {
-+ /* We use the 20 byte dev->data
-+ * for our 8 byte filter buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later */
-+ struct netdev_hw_addr *ha;
-+ u32 crc_bits;
-+
-+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
-+
-+ /* Build the multicast hash filter. */
-+ netdev_for_each_mc_addr(ha, net) {
-+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ data->multi_filter[crc_bits >> 3] |=
-+ 1 << (crc_bits & 7);
-+ }
-+
-+ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
-+ AX_MCAST_FILTER_SIZE, data->multi_filter);
-+
-+ rx_ctl |= 0x10;
-+ }
-+
-+ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
-+}
-+
-+static int ax88172_link_reset(struct usbnet *dev)
-+{
-+ u8 mode;
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ mode = AX88172_MEDIUM_DEFAULT;
-+
-+ if (ecmd.duplex != DUPLEX_FULL)
-+ mode |= ~AX88172_MEDIUM_FD;
-+
-+ netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
-+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
-+
-+ asix_write_medium_mode(dev, mode);
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops ax88172_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = asix_ioctl,
-+ .ndo_set_rx_mode = ax88172_set_multicast,
-+};
-+
-+static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret = 0;
-+ u8 buf[ETH_ALEN];
-+ int i;
-+ unsigned long gpio_bits = dev->driver_info->data;
-+
-+ usbnet_get_endpoints(dev,intf);
-+
-+ /* Toggle the GPIOs in a manufacturer/model specific way */
-+ for (i = 2; i >= 0; i--) {
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
-+ (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL);
-+ if (ret < 0)
-+ goto out;
-+ msleep(5);
-+ }
-+
-+ ret = asix_write_rx_ctl(dev, 0x80);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Get the MAC address */
-+ ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n",
-+ ret);
-+ goto out;
-+ }
-+
-+ asix_set_netdev_dev_addr(dev, buf);
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = asix_mdio_read;
-+ dev->mii.mdio_write = asix_mdio_write;
-+ dev->mii.phy_id_mask = 0x3f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.phy_id = asix_get_phy_addr(dev);
-+
-+ dev->net->netdev_ops = &ax88172_netdev_ops;
-+ dev->net->ethtool_ops = &ax88172_ethtool_ops;
-+ dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
-+ dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */
-+
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
-+ mii_nway_restart(&dev->mii);
-+
-+ return 0;
-+
-+out:
-+ return ret;
-+}
-+
-+static const struct ethtool_ops ax88772_ethtool_ops = {
-+ .get_drvinfo = asix_get_drvinfo,
-+ .get_link = asix_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = asix_get_wol,
-+ .set_wol = asix_set_wol,
-+ .get_eeprom_len = asix_get_eeprom_len,
-+ .get_eeprom = asix_get_eeprom,
-+ .set_eeprom = asix_set_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static int ax88772_link_reset(struct usbnet *dev)
-+{
-+ u16 mode;
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ mode = AX88772_MEDIUM_DEFAULT;
-+
-+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
-+ mode &= ~AX_MEDIUM_PS;
-+
-+ if (ecmd.duplex != DUPLEX_FULL)
-+ mode &= ~AX_MEDIUM_FD;
-+
-+ netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
-+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
-+
-+ asix_write_medium_mode(dev, mode);
-+
-+ return 0;
-+}
-+
-+static int ax88772_reset(struct usbnet *dev)
-+{
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ int ret, embd_phy;
-+ u16 rx_ctl;
-+
-+ ret = asix_write_gpio(dev,
-+ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5);
-+ if (ret < 0)
-+ goto out;
-+
-+ embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
-+
-+ ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
-+ goto out;
-+ }
-+
-+ ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ ret = asix_sw_reset(dev, AX_SWRESET_CLEAR);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ if (embd_phy) {
-+ ret = asix_sw_reset(dev, AX_SWRESET_IPRL);
-+ if (ret < 0)
-+ goto out;
-+ } else {
-+ ret = asix_sw_reset(dev, AX_SWRESET_PRTE);
-+ if (ret < 0)
-+ goto out;
-+ }
-+
-+ msleep(150);
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
-+ ret = asix_write_rx_ctl(dev, 0x0000);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
-+
-+ ret = asix_sw_reset(dev, AX_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA);
-+ mii_nway_restart(&dev->mii);
-+
-+ ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT);
-+ if (ret < 0)
-+ goto out;
-+
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
-+ AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
-+ AX88772_IPG2_DEFAULT, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
-+ goto out;
-+ }
-+
-+ /* Rewrite MAC address */
-+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
-+ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ rx_ctl = asix_read_medium_status(dev);
-+ netdev_dbg(dev->net,
-+ "Medium Status is 0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ return 0;
-+
-+out:
-+ return ret;
-+
-+}
-+
-+static const struct net_device_ops ax88772_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = asix_set_mac_address,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = asix_ioctl,
-+ .ndo_set_rx_mode = asix_set_multicast,
-+};
-+
-+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret, embd_phy, i;
-+ u8 buf[ETH_ALEN];
-+ u32 phyid;
-+
-+ usbnet_get_endpoints(dev,intf);
-+
-+ /* Get the MAC address */
-+ if (dev->driver_info->data & FLAG_EEPROM_MAC) {
-+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
-+ ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i,
-+ 0, 2, buf + i * 2);
-+ if (ret < 0)
-+ break;
-+ }
-+ } else {
-+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
-+ 0, 0, ETH_ALEN, buf);
-+ }
-+
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
-+ return ret;
-+ }
-+
-+ asix_set_netdev_dev_addr(dev, buf);
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = asix_mdio_read;
-+ dev->mii.mdio_write = asix_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.phy_id = asix_get_phy_addr(dev);
-+
-+ dev->net->netdev_ops = &ax88772_netdev_ops;
-+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
-+ dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
-+ dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */
-+
-+ embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
-+
-+ /* Reset the PHY to normal operation mode */
-+ ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ax88772_reset(dev);
-+
-+ /* Read PHYID register *AFTER* the PHY was reset properly */
-+ phyid = asix_get_phyid(dev);
-+ netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
-+
-+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
-+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
-+ /* hard_mtu is still the default - the device does not support
-+ jumbo eth frames */
-+ dev->rx_urb_size = 2048;
-+ }
-+
-+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
-+ if (!dev->driver_priv)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ kfree(dev->driver_priv);
-+}
-+
-+static const struct ethtool_ops ax88178_ethtool_ops = {
-+ .get_drvinfo = asix_get_drvinfo,
-+ .get_link = asix_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = asix_get_wol,
-+ .set_wol = asix_set_wol,
-+ .get_eeprom_len = asix_get_eeprom_len,
-+ .get_eeprom = asix_get_eeprom,
-+ .set_eeprom = asix_set_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static int marvell_phy_init(struct usbnet *dev)
-+{
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ u16 reg;
-+
-+ netdev_dbg(dev->net, "marvell_phy_init()\n");
-+
-+ reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
-+ netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg);
-+
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
-+ MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
-+
-+ if (data->ledmode) {
-+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
-+ MII_MARVELL_LED_CTRL);
-+ netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg);
-+
-+ reg &= 0xf8ff;
-+ reg |= (1 + 0x0100);
-+ asix_mdio_write(dev->net, dev->mii.phy_id,
-+ MII_MARVELL_LED_CTRL, reg);
-+
-+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
-+ MII_MARVELL_LED_CTRL);
-+ netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg);
-+ reg &= 0xfc0f;
-+ }
-+
-+ return 0;
-+}
-+
-+static int rtl8211cl_phy_init(struct usbnet *dev)
-+{
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+
-+ netdev_dbg(dev->net, "rtl8211cl_phy_init()\n");
-+
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005);
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0);
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x01,
-+ asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080);
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0);
-+
-+ if (data->ledmode == 12) {
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002);
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb);
-+ asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0);
-+ }
-+
-+ return 0;
-+}
-+
-+static int marvell_led_status(struct usbnet *dev, u16 speed)
-+{
-+ u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
-+
-+ netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg);
-+
-+ /* Clear out the center LED bits - 0x03F0 */
-+ reg &= 0xfc0f;
-+
-+ switch (speed) {
-+ case SPEED_1000:
-+ reg |= 0x03e0;
-+ break;
-+ case SPEED_100:
-+ reg |= 0x03b0;
-+ break;
-+ default:
-+ reg |= 0x02f0;
-+ }
-+
-+ netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg);
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
-+
-+ return 0;
-+}
-+
-+static int ax88178_reset(struct usbnet *dev)
-+{
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ int ret;
-+ __le16 eeprom;
-+ u8 status;
-+ int gpio0 = 0;
-+ u32 phyid;
-+
-+ asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
-+ netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status);
-+
-+ asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
-+ asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
-+ asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
-+
-+ netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom);
-+
-+ if (eeprom == cpu_to_le16(0xffff)) {
-+ data->phymode = PHY_MODE_MARVELL;
-+ data->ledmode = 0;
-+ gpio0 = 1;
-+ } else {
-+ data->phymode = le16_to_cpu(eeprom) & 0x7F;
-+ data->ledmode = le16_to_cpu(eeprom) >> 8;
-+ gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
-+ }
-+ netdev_dbg(dev->net, "GPIO0: %d, PhyMode: %d\n", gpio0, data->phymode);
-+
-+ /* Power up external GigaPHY through AX88178 GPIO pin */
-+ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
-+ if ((le16_to_cpu(eeprom) >> 8) != 1) {
-+ asix_write_gpio(dev, 0x003c, 30);
-+ asix_write_gpio(dev, 0x001c, 300);
-+ asix_write_gpio(dev, 0x003c, 30);
-+ } else {
-+ netdev_dbg(dev->net, "gpio phymode == 1 path\n");
-+ asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
-+ asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
-+ }
-+
-+ /* Read PHYID register *AFTER* powering up PHY */
-+ phyid = asix_get_phyid(dev);
-+ netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
-+
-+ /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */
-+ asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL);
-+
-+ asix_sw_reset(dev, 0);
-+ msleep(150);
-+
-+ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
-+ msleep(150);
-+
-+ asix_write_rx_ctl(dev, 0);
-+
-+ if (data->phymode == PHY_MODE_MARVELL) {
-+ marvell_phy_init(dev);
-+ msleep(60);
-+ } else if (data->phymode == PHY_MODE_RTL8211CL)
-+ rtl8211cl_phy_init(dev);
-+
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
-+ BMCR_RESET | BMCR_ANENABLE);
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
-+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
-+ ADVERTISE_1000FULL);
-+
-+ mii_nway_restart(&dev->mii);
-+
-+ ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Rewrite MAC address */
-+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int ax88178_link_reset(struct usbnet *dev)
-+{
-+ u16 mode;
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ u32 speed;
-+
-+ netdev_dbg(dev->net, "ax88178_link_reset()\n");
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ mode = AX88178_MEDIUM_DEFAULT;
-+ speed = ethtool_cmd_speed(&ecmd);
-+
-+ if (speed == SPEED_1000)
-+ mode |= AX_MEDIUM_GM;
-+ else if (speed == SPEED_100)
-+ mode |= AX_MEDIUM_PS;
-+ else
-+ mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
-+
-+ mode |= AX_MEDIUM_ENCK;
-+
-+ if (ecmd.duplex == DUPLEX_FULL)
-+ mode |= AX_MEDIUM_FD;
-+ else
-+ mode &= ~AX_MEDIUM_FD;
-+
-+ netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
-+ speed, ecmd.duplex, mode);
-+
-+ asix_write_medium_mode(dev, mode);
-+
-+ if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
-+ marvell_led_status(dev, speed);
-+
-+ return 0;
-+}
-+
-+static void ax88178_set_mfb(struct usbnet *dev)
-+{
-+ u16 mfb = AX_RX_CTL_MFB_16384;
-+ u16 rxctl;
-+ u16 medium;
-+ int old_rx_urb_size = dev->rx_urb_size;
-+
-+ if (dev->hard_mtu < 2048) {
-+ dev->rx_urb_size = 2048;
-+ mfb = AX_RX_CTL_MFB_2048;
-+ } else if (dev->hard_mtu < 4096) {
-+ dev->rx_urb_size = 4096;
-+ mfb = AX_RX_CTL_MFB_4096;
-+ } else if (dev->hard_mtu < 8192) {
-+ dev->rx_urb_size = 8192;
-+ mfb = AX_RX_CTL_MFB_8192;
-+ } else if (dev->hard_mtu < 16384) {
-+ dev->rx_urb_size = 16384;
-+ mfb = AX_RX_CTL_MFB_16384;
-+ }
-+
-+ rxctl = asix_read_rx_ctl(dev);
-+ asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb);
-+
-+ medium = asix_read_medium_status(dev);
-+ if (dev->net->mtu > 1500)
-+ medium |= AX_MEDIUM_JFE;
-+ else
-+ medium &= ~AX_MEDIUM_JFE;
-+ asix_write_medium_mode(dev, medium);
-+
-+ if (dev->rx_urb_size > old_rx_urb_size)
-+ usbnet_unlink_rx_urbs(dev);
-+}
-+
-+static int ax88178_change_mtu(struct net_device *net, int new_mtu)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ int ll_mtu = new_mtu + net->hard_header_len + 4;
-+
-+ netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu);
-+
-+ if (new_mtu <= 0 || ll_mtu > 16384)
-+ return -EINVAL;
-+
-+ if ((ll_mtu % dev->maxpacket) == 0)
-+ return -EDOM;
-+
-+ net->mtu = new_mtu;
-+ dev->hard_mtu = net->mtu + net->hard_header_len;
-+ ax88178_set_mfb(dev);
-+
-+ /* max qlen depend on hard_mtu and rx_urb_size */
-+ usbnet_update_max_qlen(dev);
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops ax88178_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_set_mac_address = asix_set_mac_address,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_set_rx_mode = asix_set_multicast,
-+ .ndo_do_ioctl = asix_ioctl,
-+ .ndo_change_mtu = ax88178_change_mtu,
-+};
-+
-+static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret;
-+ u8 buf[ETH_ALEN];
-+
-+ usbnet_get_endpoints(dev,intf);
-+
-+ /* Get the MAC address */
-+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
-+ return ret;
-+ }
-+
-+ asix_set_netdev_dev_addr(dev, buf);
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = asix_mdio_read;
-+ dev->mii.mdio_write = asix_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0xff;
-+ dev->mii.supports_gmii = 1;
-+ dev->mii.phy_id = asix_get_phy_addr(dev);
-+
-+ dev->net->netdev_ops = &ax88178_netdev_ops;
-+ dev->net->ethtool_ops = &ax88178_ethtool_ops;
-+
-+ /* Blink LEDS so users know driver saw dongle */
-+ asix_sw_reset(dev, 0);
-+ msleep(150);
-+
-+ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
-+ msleep(150);
-+
-+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
-+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
-+ /* hard_mtu is still the default - the device does not support
-+ jumbo eth frames */
-+ dev->rx_urb_size = 2048;
-+ }
-+
-+ dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL);
-+ if (!dev->driver_priv)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+static const struct driver_info ax8817x_info = {
-+ .description = "ASIX AX8817x USB 2.0 Ethernet",
-+ .bind = ax88172_bind,
-+ .status = asix_status,
-+ .link_reset = ax88172_link_reset,
-+ .reset = ax88172_link_reset,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .data = 0x00130103,
-+};
-+
-+static const struct driver_info dlink_dub_e100_info = {
-+ .description = "DLink DUB-E100 USB Ethernet",
-+ .bind = ax88172_bind,
-+ .status = asix_status,
-+ .link_reset = ax88172_link_reset,
-+ .reset = ax88172_link_reset,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .data = 0x009f9d9f,
-+};
-+
-+static const struct driver_info netgear_fa120_info = {
-+ .description = "Netgear FA-120 USB Ethernet",
-+ .bind = ax88172_bind,
-+ .status = asix_status,
-+ .link_reset = ax88172_link_reset,
-+ .reset = ax88172_link_reset,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .data = 0x00130103,
-+};
-+
-+static const struct driver_info hawking_uf200_info = {
-+ .description = "Hawking UF200 USB Ethernet",
-+ .bind = ax88172_bind,
-+ .status = asix_status,
-+ .link_reset = ax88172_link_reset,
-+ .reset = ax88172_link_reset,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .data = 0x001f1d1f,
-+};
-+
-+static const struct driver_info ax88772_info = {
-+ .description = "ASIX AX88772 USB 2.0 Ethernet",
-+ .bind = ax88772_bind,
-+ .unbind = ax88772_unbind,
-+ .status = asix_status,
-+ .link_reset = ax88772_link_reset,
-+ .reset = ax88772_link_reset,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET,
-+ .rx_fixup = asix_rx_fixup_common,
-+ .tx_fixup = asix_tx_fixup,
-+};
-+
-+static const struct driver_info ax88772b_info = {
-+ .description = "ASIX AX88772B USB 2.0 Ethernet",
-+ .bind = ax88772_bind,
-+ .unbind = ax88772_unbind,
-+ .status = asix_status,
-+ .link_reset = ax88772_link_reset,
-+ .reset = ax88772_reset,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-+ FLAG_MULTI_PACKET,
-+ .rx_fixup = asix_rx_fixup_common,
-+ .tx_fixup = asix_tx_fixup,
-+ .data = FLAG_EEPROM_MAC,
-+};
-+
-+static const struct driver_info ax88178_info = {
-+ .description = "ASIX AX88178 USB 2.0 Ethernet",
-+ .bind = ax88178_bind,
-+ .unbind = ax88772_unbind,
-+ .status = asix_status,
-+ .link_reset = ax88178_link_reset,
-+ .reset = ax88178_reset,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-+ FLAG_MULTI_PACKET,
-+ .rx_fixup = asix_rx_fixup_common,
-+ .tx_fixup = asix_tx_fixup,
-+};
-+
-+/*
-+ * USBLINK 20F9 "USB 2.0 LAN" USB ethernet adapter, typically found in
-+ * no-name packaging.
-+ * USB device strings are:
-+ * 1: Manufacturer: USBLINK
-+ * 2: Product: HG20F9 USB2.0
-+ * 3: Serial: 000003
-+ * Appears to be compatible with Asix 88772B.
-+ */
-+static const struct driver_info hg20f9_info = {
-+ .description = "HG20F9 USB 2.0 Ethernet",
-+ .bind = ax88772_bind,
-+ .unbind = ax88772_unbind,
-+ .status = asix_status,
-+ .link_reset = ax88772_link_reset,
-+ .reset = ax88772_reset,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-+ FLAG_MULTI_PACKET,
-+ .rx_fixup = asix_rx_fixup_common,
-+ .tx_fixup = asix_tx_fixup,
-+ .data = FLAG_EEPROM_MAC,
-+};
-+
-+static const struct usb_device_id products [] = {
-+{
-+ // Linksys USB200M
-+ USB_DEVICE (0x077b, 0x2226),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Netgear FA120
-+ USB_DEVICE (0x0846, 0x1040),
-+ .driver_info = (unsigned long) &netgear_fa120_info,
-+}, {
-+ // DLink DUB-E100
-+ USB_DEVICE (0x2001, 0x1a00),
-+ .driver_info = (unsigned long) &dlink_dub_e100_info,
-+}, {
-+ // Intellinet, ST Lab USB Ethernet
-+ USB_DEVICE (0x0b95, 0x1720),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Hawking UF200, TrendNet TU2-ET100
-+ USB_DEVICE (0x07b8, 0x420a),
-+ .driver_info = (unsigned long) &hawking_uf200_info,
-+}, {
-+ // Billionton Systems, USB2AR
-+ USB_DEVICE (0x08dd, 0x90ff),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // ATEN UC210T
-+ USB_DEVICE (0x0557, 0x2009),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Buffalo LUA-U2-KTX
-+ USB_DEVICE (0x0411, 0x003d),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Buffalo LUA-U2-GT 10/100/1000
-+ USB_DEVICE (0x0411, 0x006e),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
-+ USB_DEVICE (0x6189, 0x182d),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter"
-+ USB_DEVICE (0x0df6, 0x0056),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Sitecom LN-028 "USB 2.0 10/100/1000 Ethernet adapter"
-+ USB_DEVICE (0x0df6, 0x061c),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // corega FEther USB2-TX
-+ USB_DEVICE (0x07aa, 0x0017),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Surecom EP-1427X-2
-+ USB_DEVICE (0x1189, 0x0893),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // goodway corp usb gwusb2e
-+ USB_DEVICE (0x1631, 0x6200),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // JVC MP-PRX1 Port Replicator
-+ USB_DEVICE (0x04f1, 0x3008),
-+ .driver_info = (unsigned long) &ax8817x_info,
-+}, {
-+ // Lenovo U2L100P 10/100
-+ USB_DEVICE (0x17ef, 0x7203),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // ASIX AX88772B 10/100
-+ USB_DEVICE (0x0b95, 0x772b),
-+ .driver_info = (unsigned long) &ax88772b_info,
-+}, {
-+ // ASIX AX88772 10/100
-+ USB_DEVICE (0x0b95, 0x7720),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // ASIX AX88178 10/100/1000
-+ USB_DEVICE (0x0b95, 0x1780),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Logitec LAN-GTJ/U2A
-+ USB_DEVICE (0x0789, 0x0160),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Linksys USB200M Rev 2
-+ USB_DEVICE (0x13b1, 0x0018),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // 0Q0 cable ethernet
-+ USB_DEVICE (0x1557, 0x7720),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // DLink DUB-E100 H/W Ver B1
-+ USB_DEVICE (0x07d1, 0x3c05),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // DLink DUB-E100 H/W Ver B1 Alternate
-+ USB_DEVICE (0x2001, 0x3c05),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // DLink DUB-E100 H/W Ver C1
-+ USB_DEVICE (0x2001, 0x1a02),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // Linksys USB1000
-+ USB_DEVICE (0x1737, 0x0039),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // IO-DATA ETG-US2
-+ USB_DEVICE (0x04bb, 0x0930),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Belkin F5D5055
-+ USB_DEVICE(0x050d, 0x5055),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // Apple USB Ethernet Adapter
-+ USB_DEVICE(0x05ac, 0x1402),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // Cables-to-Go USB Ethernet Adapter
-+ USB_DEVICE(0x0b95, 0x772a),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // ABOCOM for pci
-+ USB_DEVICE(0x14ea, 0xab11),
-+ .driver_info = (unsigned long) &ax88178_info,
-+}, {
-+ // ASIX 88772a
-+ USB_DEVICE(0x0db0, 0xa877),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ // Asus USB Ethernet Adapter
-+ USB_DEVICE (0x0b95, 0x7e2b),
-+ .driver_info = (unsigned long) &ax88772_info,
-+}, {
-+ /* ASIX 88172a demo board */
-+ USB_DEVICE(0x0b95, 0x172a),
-+ .driver_info = (unsigned long) &ax88172a_info,
-+}, {
-+ /*
-+ * USBLINK HG20F9 "USB 2.0 LAN"
-+ * Appears to have gazumped Linksys's manufacturer ID but
-+ * doesn't (yet) conflict with any known Linksys product.
-+ */
-+ USB_DEVICE(0x066b, 0x20f9),
-+ .driver_info = (unsigned long) &hg20f9_info,
-+},
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver asix_driver = {
-+ .name = DRIVER_NAME,
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disconnect = usbnet_disconnect,
-+ .supports_autosuspend = 1,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(asix_driver);
-+
-+MODULE_AUTHOR("David Hollis");
-+MODULE_VERSION(DRIVER_VERSION);
-+MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices");
-+MODULE_LICENSE("GPL");
-+
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/asix.h backports-4.2.6-1/drivers/net/usb/asix.h
---- backports-4.2.6-1.org/drivers/net/usb/asix.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/asix.h 2016-06-28 14:35:17.965307221 +0200
-@@ -0,0 +1,234 @@
-+/*
-+ * ASIX AX8817X based USB 2.0 Ethernet Devices
-+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
-+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
-+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
-+ * Copyright (c) 2002-2003 TiVo Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _ASIX_H
-+#define _ASIX_H
-+
-+// #define DEBUG // error path messages, extra info
-+// #define VERBOSE // more; success messages
-+
-+#include <linux/module.h>
-+#include <linux/kmod.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+#include <linux/if_vlan.h>
-+
-+#define DRIVER_VERSION "22-Dec-2011"
-+#define DRIVER_NAME "asix"
-+
-+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
-+
-+#define AX_CMD_SET_SW_MII 0x06
-+#define AX_CMD_READ_MII_REG 0x07
-+#define AX_CMD_WRITE_MII_REG 0x08
-+#define AX_CMD_SET_HW_MII 0x0a
-+#define AX_CMD_READ_EEPROM 0x0b
-+#define AX_CMD_WRITE_EEPROM 0x0c
-+#define AX_CMD_WRITE_ENABLE 0x0d
-+#define AX_CMD_WRITE_DISABLE 0x0e
-+#define AX_CMD_READ_RX_CTL 0x0f
-+#define AX_CMD_WRITE_RX_CTL 0x10
-+#define AX_CMD_READ_IPG012 0x11
-+#define AX_CMD_WRITE_IPG0 0x12
-+#define AX_CMD_WRITE_IPG1 0x13
-+#define AX_CMD_READ_NODE_ID 0x13
-+#define AX_CMD_WRITE_NODE_ID 0x14
-+#define AX_CMD_WRITE_IPG2 0x14
-+#define AX_CMD_WRITE_MULTI_FILTER 0x16
-+#define AX88172_CMD_READ_NODE_ID 0x17
-+#define AX_CMD_READ_PHY_ID 0x19
-+#define AX_CMD_READ_MEDIUM_STATUS 0x1a
-+#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
-+#define AX_CMD_READ_MONITOR_MODE 0x1c
-+#define AX_CMD_WRITE_MONITOR_MODE 0x1d
-+#define AX_CMD_READ_GPIOS 0x1e
-+#define AX_CMD_WRITE_GPIOS 0x1f
-+#define AX_CMD_SW_RESET 0x20
-+#define AX_CMD_SW_PHY_STATUS 0x21
-+#define AX_CMD_SW_PHY_SELECT 0x22
-+
-+#define AX_PHY_SELECT_MASK (BIT(3) | BIT(2))
-+#define AX_PHY_SELECT_INTERNAL 0
-+#define AX_PHY_SELECT_EXTERNAL BIT(2)
-+
-+#define AX_MONITOR_MODE 0x01
-+#define AX_MONITOR_LINK 0x02
-+#define AX_MONITOR_MAGIC 0x04
-+#define AX_MONITOR_HSFS 0x10
-+
-+/* AX88172 Medium Status Register values */
-+#define AX88172_MEDIUM_FD 0x02
-+#define AX88172_MEDIUM_TX 0x04
-+#define AX88172_MEDIUM_FC 0x10
-+#define AX88172_MEDIUM_DEFAULT \
-+ ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
-+
-+#define AX_MCAST_FILTER_SIZE 8
-+#define AX_MAX_MCAST 64
-+
-+#define AX_SWRESET_CLEAR 0x00
-+#define AX_SWRESET_RR 0x01
-+#define AX_SWRESET_RT 0x02
-+#define AX_SWRESET_PRTE 0x04
-+#define AX_SWRESET_PRL 0x08
-+#define AX_SWRESET_BZ 0x10
-+#define AX_SWRESET_IPRL 0x20
-+#define AX_SWRESET_IPPD 0x40
-+
-+#define AX88772_IPG0_DEFAULT 0x15
-+#define AX88772_IPG1_DEFAULT 0x0c
-+#define AX88772_IPG2_DEFAULT 0x12
-+
-+/* AX88772 & AX88178 Medium Mode Register */
-+#define AX_MEDIUM_PF 0x0080
-+#define AX_MEDIUM_JFE 0x0040
-+#define AX_MEDIUM_TFC 0x0020
-+#define AX_MEDIUM_RFC 0x0010
-+#define AX_MEDIUM_ENCK 0x0008
-+#define AX_MEDIUM_AC 0x0004
-+#define AX_MEDIUM_FD 0x0002
-+#define AX_MEDIUM_GM 0x0001
-+#define AX_MEDIUM_SM 0x1000
-+#define AX_MEDIUM_SBP 0x0800
-+#define AX_MEDIUM_PS 0x0200
-+#define AX_MEDIUM_RE 0x0100
-+
-+#define AX88178_MEDIUM_DEFAULT \
-+ (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
-+ AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
-+ AX_MEDIUM_RE)
-+
-+#define AX88772_MEDIUM_DEFAULT \
-+ (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
-+ AX_MEDIUM_TFC | AX_MEDIUM_PS | \
-+ AX_MEDIUM_AC | AX_MEDIUM_RE)
-+
-+/* AX88772 & AX88178 RX_CTL values */
-+#define AX_RX_CTL_SO 0x0080
-+#define AX_RX_CTL_AP 0x0020
-+#define AX_RX_CTL_AM 0x0010
-+#define AX_RX_CTL_AB 0x0008
-+#define AX_RX_CTL_SEP 0x0004
-+#define AX_RX_CTL_AMALL 0x0002
-+#define AX_RX_CTL_PRO 0x0001
-+#define AX_RX_CTL_MFB_2048 0x0000
-+#define AX_RX_CTL_MFB_4096 0x0100
-+#define AX_RX_CTL_MFB_8192 0x0200
-+#define AX_RX_CTL_MFB_16384 0x0300
-+
-+#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB)
-+
-+/* GPIO 0 .. 2 toggles */
-+#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
-+#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
-+#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
-+#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
-+#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
-+#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
-+#define AX_GPIO_RESERVED 0x40 /* Reserved */
-+#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
-+
-+#define AX_EEPROM_MAGIC 0xdeadbeef
-+#define AX_EEPROM_LEN 0x200
-+
-+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
-+struct asix_data {
-+ u8 multi_filter[AX_MCAST_FILTER_SIZE];
-+ u8 mac_addr[ETH_ALEN];
-+ u8 phymode;
-+ u8 ledmode;
-+ u8 res;
-+};
-+
-+struct asix_rx_fixup_info {
-+ struct sk_buff *ax_skb;
-+ u32 header;
-+ u16 size;
-+ bool split_head;
-+};
-+
-+struct asix_common_private {
-+ struct asix_rx_fixup_info rx_fixup_info;
-+};
-+
-+extern const struct driver_info ax88172a_info;
-+
-+/* ASIX specific flags */
-+#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */
-+
-+int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data);
-+
-+int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data);
-+
-+void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
-+ u16 index, u16 size, void *data);
-+
-+int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
-+ struct asix_rx_fixup_info *rx);
-+int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb);
-+
-+struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags);
-+
-+int asix_set_sw_mii(struct usbnet *dev);
-+int asix_set_hw_mii(struct usbnet *dev);
-+
-+int asix_read_phy_addr(struct usbnet *dev, int internal);
-+int asix_get_phy_addr(struct usbnet *dev);
-+
-+int asix_sw_reset(struct usbnet *dev, u8 flags);
-+
-+u16 asix_read_rx_ctl(struct usbnet *dev);
-+int asix_write_rx_ctl(struct usbnet *dev, u16 mode);
-+
-+u16 asix_read_medium_status(struct usbnet *dev);
-+int asix_write_medium_mode(struct usbnet *dev, u16 mode);
-+
-+int asix_write_gpio(struct usbnet *dev, u16 value, int sleep);
-+
-+void asix_set_multicast(struct net_device *net);
-+
-+int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);
-+void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);
-+
-+void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
-+int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo);
-+
-+int asix_get_eeprom_len(struct net_device *net);
-+int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
-+ u8 *data);
-+int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
-+ u8 *data);
-+
-+void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info);
-+
-+int asix_set_mac_address(struct net_device *net, void *p);
-+
-+#endif /* _ASIX_H */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/ax88172a.c backports-4.2.6-1/drivers/net/usb/ax88172a.c
---- backports-4.2.6-1.org/drivers/net/usb/ax88172a.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/ax88172a.c 2016-06-28 14:35:17.965307221 +0200
-@@ -0,0 +1,422 @@
-+/*
-+ * ASIX AX88172A based USB 2.0 Ethernet Devices
-+ * Copyright (C) 2012 OMICRON electronics GmbH
-+ *
-+ * Supports external PHYs via phylib. Based on the driver for the
-+ * AX88772. Original copyrights follow:
-+ *
-+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
-+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
-+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
-+ * Copyright (c) 2002-2003 TiVo Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "asix.h"
-+#include <linux/phy.h>
-+
-+struct ax88172a_private {
-+ struct mii_bus *mdio;
-+ struct phy_device *phydev;
-+ char phy_name[20];
-+ u16 phy_addr;
-+ u16 oldmode;
-+ int use_embdphy;
-+ struct asix_rx_fixup_info rx_fixup_info;
-+};
-+
-+/* MDIO read and write wrappers for phylib */
-+static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)
-+{
-+ return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id,
-+ regnum);
-+}
-+
-+static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum,
-+ u16 val)
-+{
-+ asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val);
-+ return 0;
-+}
-+
-+static int ax88172a_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ if (!netif_running(net))
-+ return -EINVAL;
-+
-+ if (!net->phydev)
-+ return -ENODEV;
-+
-+ return phy_mii_ioctl(net->phydev, rq, cmd);
-+}
-+
-+/* set MAC link settings according to information from phylib */
-+static void ax88172a_adjust_link(struct net_device *netdev)
-+{
-+ struct phy_device *phydev = netdev->phydev;
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct ax88172a_private *priv = dev->driver_priv;
-+ u16 mode = 0;
-+
-+ if (phydev->link) {
-+ mode = AX88772_MEDIUM_DEFAULT;
-+
-+ if (phydev->duplex == DUPLEX_HALF)
-+ mode &= ~AX_MEDIUM_FD;
-+
-+ if (phydev->speed != SPEED_100)
-+ mode &= ~AX_MEDIUM_PS;
-+ }
-+
-+ if (mode != priv->oldmode) {
-+ asix_write_medium_mode(dev, mode);
-+ priv->oldmode = mode;
-+ netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n",
-+ phydev->speed, phydev->duplex, mode);
-+ phy_print_status(phydev);
-+ }
-+}
-+
-+static void ax88172a_status(struct usbnet *dev, struct urb *urb)
-+{
-+ /* link changes are detected by polling the phy */
-+}
-+
-+/* use phylib infrastructure */
-+static int ax88172a_init_mdio(struct usbnet *dev)
-+{
-+ struct ax88172a_private *priv = dev->driver_priv;
-+ int ret, i;
-+
-+ priv->mdio = mdiobus_alloc();
-+ if (!priv->mdio) {
-+ netdev_err(dev->net, "Could not allocate MDIO bus\n");
-+ return -ENOMEM;
-+ }
-+
-+ priv->mdio->priv = (void *)dev;
-+ priv->mdio->read = &asix_mdio_bus_read;
-+ priv->mdio->write = &asix_mdio_bus_write;
-+ priv->mdio->name = "Asix MDIO Bus";
-+ /* mii bus name is usb-<usb bus number>-<usb device number> */
-+ snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
-+ dev->udev->bus->busnum, dev->udev->devnum);
-+
-+ priv->mdio->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-+ if (!priv->mdio->irq) {
-+ ret = -ENOMEM;
-+ goto mfree;
-+ }
-+ for (i = 0; i < PHY_MAX_ADDR; i++)
-+ priv->mdio->irq[i] = PHY_POLL;
-+
-+ ret = mdiobus_register(priv->mdio);
-+ if (ret) {
-+ netdev_err(dev->net, "Could not register MDIO bus\n");
-+ goto ifree;
-+ }
-+
-+ netdev_info(dev->net, "registered mdio bus %s\n", priv->mdio->id);
-+ return 0;
-+
-+ifree:
-+ kfree(priv->mdio->irq);
-+mfree:
-+ mdiobus_free(priv->mdio);
-+ return ret;
-+}
-+
-+static void ax88172a_remove_mdio(struct usbnet *dev)
-+{
-+ struct ax88172a_private *priv = dev->driver_priv;
-+
-+ netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id);
-+ mdiobus_unregister(priv->mdio);
-+ kfree(priv->mdio->irq);
-+ mdiobus_free(priv->mdio);
-+}
-+
-+static const struct net_device_ops ax88172a_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = asix_set_mac_address,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = ax88172a_ioctl,
-+ .ndo_set_rx_mode = asix_set_multicast,
-+};
-+
-+static int ax88172a_get_settings(struct net_device *net,
-+ struct ethtool_cmd *cmd)
-+{
-+ if (!net->phydev)
-+ return -ENODEV;
-+
-+ return phy_ethtool_gset(net->phydev, cmd);
-+}
-+
-+static int ax88172a_set_settings(struct net_device *net,
-+ struct ethtool_cmd *cmd)
-+{
-+ if (!net->phydev)
-+ return -ENODEV;
-+
-+ return phy_ethtool_sset(net->phydev, cmd);
-+}
-+
-+static int ax88172a_nway_reset(struct net_device *net)
-+{
-+ if (!net->phydev)
-+ return -ENODEV;
-+
-+ return phy_start_aneg(net->phydev);
-+}
-+
-+static const struct ethtool_ops ax88172a_ethtool_ops = {
-+ .get_drvinfo = asix_get_drvinfo,
-+ .get_link = usbnet_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = asix_get_wol,
-+ .set_wol = asix_set_wol,
-+ .get_eeprom_len = asix_get_eeprom_len,
-+ .get_eeprom = asix_get_eeprom,
-+ .set_eeprom = asix_set_eeprom,
-+ .get_settings = ax88172a_get_settings,
-+ .set_settings = ax88172a_set_settings,
-+ .nway_reset = ax88172a_nway_reset,
-+};
-+
-+static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy)
-+{
-+ int ret;
-+
-+ ret = asix_sw_reset(dev, AX_SWRESET_IPPD);
-+ if (ret < 0)
-+ goto err;
-+
-+ msleep(150);
-+ ret = asix_sw_reset(dev, AX_SWRESET_CLEAR);
-+ if (ret < 0)
-+ goto err;
-+
-+ msleep(150);
-+
-+ ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD);
-+ if (ret < 0)
-+ goto err;
-+
-+ return 0;
-+
-+err:
-+ return ret;
-+}
-+
-+
-+static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret;
-+ u8 buf[ETH_ALEN];
-+ struct ax88172a_private *priv;
-+
-+ usbnet_get_endpoints(dev, intf);
-+
-+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ return -ENOMEM;
-+
-+ dev->driver_priv = priv;
-+
-+ /* Get the MAC address */
-+ ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to read MAC address: %d\n", ret);
-+ goto free;
-+ }
-+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
-+
-+ dev->net->netdev_ops = &ax88172a_netdev_ops;
-+ dev->net->ethtool_ops = &ax88172a_ethtool_ops;
-+
-+ /* are we using the internal or the external phy? */
-+ ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to read software interface selection register: %d\n",
-+ ret);
-+ goto free;
-+ }
-+
-+ netdev_dbg(dev->net, "AX_CMD_SW_PHY_STATUS = 0x%02x\n", buf[0]);
-+ switch (buf[0] & AX_PHY_SELECT_MASK) {
-+ case AX_PHY_SELECT_INTERNAL:
-+ netdev_dbg(dev->net, "use internal phy\n");
-+ priv->use_embdphy = 1;
-+ break;
-+ case AX_PHY_SELECT_EXTERNAL:
-+ netdev_dbg(dev->net, "use external phy\n");
-+ priv->use_embdphy = 0;
-+ break;
-+ default:
-+ netdev_err(dev->net, "Interface mode not supported by driver\n");
-+ ret = -ENOTSUPP;
-+ goto free;
-+ }
-+
-+ priv->phy_addr = asix_read_phy_addr(dev, priv->use_embdphy);
-+ ax88172a_reset_phy(dev, priv->use_embdphy);
-+
-+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
-+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
-+ /* hard_mtu is still the default - the device does not support
-+ jumbo eth frames */
-+ dev->rx_urb_size = 2048;
-+ }
-+
-+ /* init MDIO bus */
-+ ret = ax88172a_init_mdio(dev);
-+ if (ret)
-+ goto free;
-+
-+ return 0;
-+
-+free:
-+ kfree(priv);
-+ return ret;
-+}
-+
-+static int ax88172a_stop(struct usbnet *dev)
-+{
-+ struct ax88172a_private *priv = dev->driver_priv;
-+
-+ netdev_dbg(dev->net, "Stopping interface\n");
-+
-+ if (priv->phydev) {
-+ netdev_info(dev->net, "Disconnecting from phy %s\n",
-+ priv->phy_name);
-+ phy_stop(priv->phydev);
-+ phy_disconnect(priv->phydev);
-+ }
-+
-+ return 0;
-+}
-+
-+static void ax88172a_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct ax88172a_private *priv = dev->driver_priv;
-+
-+ ax88172a_remove_mdio(dev);
-+ kfree(priv);
-+}
-+
-+static int ax88172a_reset(struct usbnet *dev)
-+{
-+ struct asix_data *data = (struct asix_data *)&dev->data;
-+ struct ax88172a_private *priv = dev->driver_priv;
-+ int ret;
-+ u16 rx_ctl;
-+
-+ ax88172a_reset_phy(dev, priv->use_embdphy);
-+
-+ msleep(150);
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
-+ ret = asix_write_rx_ctl(dev, 0x0000);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
-+
-+ msleep(150);
-+
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
-+ AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
-+ AX88772_IPG2_DEFAULT, 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
-+ goto out;
-+ }
-+
-+ /* Rewrite MAC address */
-+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
-+ ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
-+ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = asix_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ rx_ctl = asix_read_medium_status(dev);
-+ netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ /* Connect to PHY */
-+ snprintf(priv->phy_name, 20, PHY_ID_FMT,
-+ priv->mdio->id, priv->phy_addr);
-+
-+ priv->phydev = phy_connect(dev->net, priv->phy_name,
-+ &ax88172a_adjust_link,
-+ PHY_INTERFACE_MODE_MII);
-+ if (IS_ERR(priv->phydev)) {
-+ netdev_err(dev->net, "Could not connect to PHY device %s\n",
-+ priv->phy_name);
-+ ret = PTR_ERR(priv->phydev);
-+ goto out;
-+ }
-+
-+ netdev_info(dev->net, "Connected to phy %s\n", priv->phy_name);
-+
-+ /* During power-up, the AX88172A set the power down (BMCR_PDOWN)
-+ * bit of the PHY. Bring the PHY up again.
-+ */
-+ genphy_resume(priv->phydev);
-+ phy_start(priv->phydev);
-+
-+ return 0;
-+
-+out:
-+ return ret;
-+
-+}
-+
-+static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct ax88172a_private *dp = dev->driver_priv;
-+ struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;
-+
-+ return asix_rx_fixup_internal(dev, skb, rx);
-+}
-+
-+const struct driver_info ax88172a_info = {
-+ .description = "ASIX AX88172A USB 2.0 Ethernet",
-+ .bind = ax88172a_bind,
-+ .reset = ax88172a_reset,
-+ .stop = ax88172a_stop,
-+ .unbind = ax88172a_unbind,
-+ .status = ax88172a_status,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
-+ FLAG_MULTI_PACKET,
-+ .rx_fixup = ax88172a_rx_fixup,
-+ .tx_fixup = asix_tx_fixup,
-+};
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/ax88179_178a.c backports-4.2.6-1/drivers/net/usb/ax88179_178a.c
---- backports-4.2.6-1.org/drivers/net/usb/ax88179_178a.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/ax88179_178a.c 2016-06-28 14:35:17.968640554 +0200
-@@ -0,0 +1,1756 @@
-+/*
-+ * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices
-+ *
-+ * Copyright (C) 2011-2013 ASIX
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/etherdevice.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <uapi/linux/mdio.h>
-+#include <linux/mdio.h>
-+
-+#define AX88179_PHY_ID 0x03
-+#define AX_EEPROM_LEN 0x100
-+#define AX88179_EEPROM_MAGIC 0x17900b95
-+#define AX_MCAST_FLTSIZE 8
-+#define AX_MAX_MCAST 64
-+#define AX_INT_PPLS_LINK ((u32)BIT(16))
-+#define AX_RXHDR_L4_TYPE_MASK 0x1c
-+#define AX_RXHDR_L4_TYPE_UDP 4
-+#define AX_RXHDR_L4_TYPE_TCP 16
-+#define AX_RXHDR_L3CSUM_ERR 2
-+#define AX_RXHDR_L4CSUM_ERR 1
-+#define AX_RXHDR_CRC_ERR ((u32)BIT(29))
-+#define AX_RXHDR_DROP_ERR ((u32)BIT(31))
-+#define AX_ACCESS_MAC 0x01
-+#define AX_ACCESS_PHY 0x02
-+#define AX_ACCESS_EEPROM 0x04
-+#define AX_ACCESS_EFUS 0x05
-+#define AX_PAUSE_WATERLVL_HIGH 0x54
-+#define AX_PAUSE_WATERLVL_LOW 0x55
-+
-+#define PHYSICAL_LINK_STATUS 0x02
-+ #define AX_USB_SS 0x04
-+ #define AX_USB_HS 0x02
-+
-+#define GENERAL_STATUS 0x03
-+/* Check AX88179 version. UA1:Bit2 = 0, UA2:Bit2 = 1 */
-+ #define AX_SECLD 0x04
-+
-+#define AX_SROM_ADDR 0x07
-+#define AX_SROM_CMD 0x0a
-+ #define EEP_RD 0x04
-+ #define EEP_BUSY 0x10
-+
-+#define AX_SROM_DATA_LOW 0x08
-+#define AX_SROM_DATA_HIGH 0x09
-+
-+#define AX_RX_CTL 0x0b
-+ #define AX_RX_CTL_DROPCRCERR 0x0100
-+ #define AX_RX_CTL_IPE 0x0200
-+ #define AX_RX_CTL_START 0x0080
-+ #define AX_RX_CTL_AP 0x0020
-+ #define AX_RX_CTL_AM 0x0010
-+ #define AX_RX_CTL_AB 0x0008
-+ #define AX_RX_CTL_AMALL 0x0002
-+ #define AX_RX_CTL_PRO 0x0001
-+ #define AX_RX_CTL_STOP 0x0000
-+
-+#define AX_NODE_ID 0x10
-+#define AX_MULFLTARY 0x16
-+
-+#define AX_MEDIUM_STATUS_MODE 0x22
-+ #define AX_MEDIUM_GIGAMODE 0x01
-+ #define AX_MEDIUM_FULL_DUPLEX 0x02
-+ #define AX_MEDIUM_EN_125MHZ 0x08
-+ #define AX_MEDIUM_RXFLOW_CTRLEN 0x10
-+ #define AX_MEDIUM_TXFLOW_CTRLEN 0x20
-+ #define AX_MEDIUM_RECEIVE_EN 0x100
-+ #define AX_MEDIUM_PS 0x200
-+ #define AX_MEDIUM_JUMBO_EN 0x8040
-+
-+#define AX_MONITOR_MOD 0x24
-+ #define AX_MONITOR_MODE_RWLC 0x02
-+ #define AX_MONITOR_MODE_RWMP 0x04
-+ #define AX_MONITOR_MODE_PMEPOL 0x20
-+ #define AX_MONITOR_MODE_PMETYPE 0x40
-+
-+#define AX_GPIO_CTRL 0x25
-+ #define AX_GPIO_CTRL_GPIO3EN 0x80
-+ #define AX_GPIO_CTRL_GPIO2EN 0x40
-+ #define AX_GPIO_CTRL_GPIO1EN 0x20
-+
-+#define AX_PHYPWR_RSTCTL 0x26
-+ #define AX_PHYPWR_RSTCTL_BZ 0x0010
-+ #define AX_PHYPWR_RSTCTL_IPRL 0x0020
-+ #define AX_PHYPWR_RSTCTL_AT 0x1000
-+
-+#define AX_RX_BULKIN_QCTRL 0x2e
-+#define AX_CLK_SELECT 0x33
-+ #define AX_CLK_SELECT_BCS 0x01
-+ #define AX_CLK_SELECT_ACS 0x02
-+ #define AX_CLK_SELECT_ULR 0x08
-+
-+#define AX_RXCOE_CTL 0x34
-+ #define AX_RXCOE_IP 0x01
-+ #define AX_RXCOE_TCP 0x02
-+ #define AX_RXCOE_UDP 0x04
-+ #define AX_RXCOE_TCPV6 0x20
-+ #define AX_RXCOE_UDPV6 0x40
-+
-+#define AX_TXCOE_CTL 0x35
-+ #define AX_TXCOE_IP 0x01
-+ #define AX_TXCOE_TCP 0x02
-+ #define AX_TXCOE_UDP 0x04
-+ #define AX_TXCOE_TCPV6 0x20
-+ #define AX_TXCOE_UDPV6 0x40
-+
-+#define AX_LEDCTRL 0x73
-+
-+#define GMII_PHY_PHYSR 0x11
-+ #define GMII_PHY_PHYSR_SMASK 0xc000
-+ #define GMII_PHY_PHYSR_GIGA 0x8000
-+ #define GMII_PHY_PHYSR_100 0x4000
-+ #define GMII_PHY_PHYSR_FULL 0x2000
-+ #define GMII_PHY_PHYSR_LINK 0x400
-+
-+#define GMII_LED_ACT 0x1a
-+ #define GMII_LED_ACTIVE_MASK 0xff8f
-+ #define GMII_LED0_ACTIVE BIT(4)
-+ #define GMII_LED1_ACTIVE BIT(5)
-+ #define GMII_LED2_ACTIVE BIT(6)
-+
-+#define GMII_LED_LINK 0x1c
-+ #define GMII_LED_LINK_MASK 0xf888
-+ #define GMII_LED0_LINK_10 BIT(0)
-+ #define GMII_LED0_LINK_100 BIT(1)
-+ #define GMII_LED0_LINK_1000 BIT(2)
-+ #define GMII_LED1_LINK_10 BIT(4)
-+ #define GMII_LED1_LINK_100 BIT(5)
-+ #define GMII_LED1_LINK_1000 BIT(6)
-+ #define GMII_LED2_LINK_10 BIT(8)
-+ #define GMII_LED2_LINK_100 BIT(9)
-+ #define GMII_LED2_LINK_1000 BIT(10)
-+ #define LED0_ACTIVE BIT(0)
-+ #define LED0_LINK_10 BIT(1)
-+ #define LED0_LINK_100 BIT(2)
-+ #define LED0_LINK_1000 BIT(3)
-+ #define LED0_FD BIT(4)
-+ #define LED0_USB3_MASK 0x001f
-+ #define LED1_ACTIVE BIT(5)
-+ #define LED1_LINK_10 BIT(6)
-+ #define LED1_LINK_100 BIT(7)
-+ #define LED1_LINK_1000 BIT(8)
-+ #define LED1_FD BIT(9)
-+ #define LED1_USB3_MASK 0x03e0
-+ #define LED2_ACTIVE BIT(10)
-+ #define LED2_LINK_1000 BIT(13)
-+ #define LED2_LINK_100 BIT(12)
-+ #define LED2_LINK_10 BIT(11)
-+ #define LED2_FD BIT(14)
-+ #define LED_VALID BIT(15)
-+ #define LED2_USB3_MASK 0x7c00
-+
-+#define GMII_PHYPAGE 0x1e
-+#define GMII_PHY_PAGE_SELECT 0x1f
-+ #define GMII_PHY_PGSEL_EXT 0x0007
-+ #define GMII_PHY_PGSEL_PAGE0 0x0000
-+ #define GMII_PHY_PGSEL_PAGE3 0x0003
-+ #define GMII_PHY_PGSEL_PAGE5 0x0005
-+
-+struct ax88179_data {
-+ u8 eee_enabled;
-+ u8 eee_active;
-+ u16 rxctl;
-+ u16 reserved;
-+};
-+
-+struct ax88179_int_data {
-+ __le32 intdata1;
-+ __le32 intdata2;
-+};
-+
-+static const struct {
-+ unsigned char ctrl, timer_l, timer_h, size, ifg;
-+} AX88179_BULKIN_SIZE[] = {
-+ {7, 0x4f, 0, 0x12, 0xff},
-+ {7, 0x20, 3, 0x16, 0xff},
-+ {7, 0xae, 7, 0x18, 0xff},
-+ {7, 0xcc, 0x4c, 0x18, 8},
-+};
-+
-+static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data, int in_pm)
-+{
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_read_cmd;
-+ else
-+ fn = usbnet_read_cmd_nopm;
-+
-+ ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, index, data, size);
-+
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
-+ index, ret);
-+
-+ return ret;
-+}
-+
-+static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data, int in_pm)
-+{
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_write_cmd;
-+ else
-+ fn = usbnet_write_cmd_nopm;
-+
-+ ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, index, data, size);
-+
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
-+ index, ret);
-+
-+ return ret;
-+}
-+
-+static void ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value,
-+ u16 index, u16 size, void *data)
-+{
-+ u16 buf;
-+
-+ if (2 == size) {
-+ buf = *((u16 *)data);
-+ cpu_to_le16s(&buf);
-+ usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE, value, index, &buf,
-+ size);
-+ } else {
-+ usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE, value, index, data,
-+ size);
-+ }
-+}
-+
-+static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
-+ u16 index, u16 size, void *data)
-+{
-+ int ret;
-+
-+ if (2 == size) {
-+ u16 buf;
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
-+ le16_to_cpus(&buf);
-+ *((u16 *)data) = buf;
-+ } else if (4 == size) {
-+ u32 buf;
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
-+ le32_to_cpus(&buf);
-+ *((u32 *)data) = buf;
-+ } else {
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
-+ u16 index, u16 size, void *data)
-+{
-+ int ret;
-+
-+ if (2 == size) {
-+ u16 buf;
-+ buf = *((u16 *)data);
-+ cpu_to_le16s(&buf);
-+ ret = __ax88179_write_cmd(dev, cmd, value, index,
-+ size, &buf, 1);
-+ } else {
-+ ret = __ax88179_write_cmd(dev, cmd, value, index,
-+ size, data, 1);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ int ret;
-+
-+ if (2 == size) {
-+ u16 buf;
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
-+ le16_to_cpus(&buf);
-+ *((u16 *)data) = buf;
-+ } else if (4 == size) {
-+ u32 buf;
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
-+ le32_to_cpus(&buf);
-+ *((u32 *)data) = buf;
-+ } else {
-+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ int ret;
-+
-+ if (2 == size) {
-+ u16 buf;
-+ buf = *((u16 *)data);
-+ cpu_to_le16s(&buf);
-+ ret = __ax88179_write_cmd(dev, cmd, value, index,
-+ size, &buf, 0);
-+ } else {
-+ ret = __ax88179_write_cmd(dev, cmd, value, index,
-+ size, data, 0);
-+ }
-+
-+ return ret;
-+}
-+
-+static void ax88179_status(struct usbnet *dev, struct urb *urb)
-+{
-+ struct ax88179_int_data *event;
-+ u32 link;
-+
-+ if (urb->actual_length < 8)
-+ return;
-+
-+ event = urb->transfer_buffer;
-+ le32_to_cpus((void *)&event->intdata1);
-+
-+ link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16;
-+
-+ if (netif_carrier_ok(dev->net) != link) {
-+ usbnet_link_change(dev, link, 1);
-+ netdev_info(dev->net, "ax88179 - Link status is: %d\n", link);
-+ }
-+}
-+
-+static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u16 res;
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
-+ return res;
-+}
-+
-+static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,
-+ int val)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u16 res = (u16) val;
-+
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
-+}
-+
-+static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad,
-+ u16 devad)
-+{
-+ u16 tmp16;
-+ int ret;
-+
-+ tmp16 = devad;
-+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_MMD_CTRL, 2, &tmp16);
-+
-+ tmp16 = prtad;
-+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_MMD_DATA, 2, &tmp16);
-+
-+ tmp16 = devad | MII_MMD_CTRL_NOINCR;
-+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_MMD_CTRL, 2, &tmp16);
-+
-+ return ret;
-+}
-+
-+static int
-+ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad)
-+{
-+ int ret;
-+ u16 tmp16;
-+
-+ ax88179_phy_mmd_indirect(dev, prtad, devad);
-+
-+ ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_MMD_DATA, 2, &tmp16);
-+ if (ret < 0)
-+ return ret;
-+
-+ return tmp16;
-+}
-+
-+static int
-+ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad,
-+ u16 data)
-+{
-+ int ret;
-+
-+ ax88179_phy_mmd_indirect(dev, prtad, devad);
-+
-+ ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_MMD_DATA, 2, &data);
-+
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int ax88179_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ u16 tmp16;
-+ u8 tmp8;
-+
-+ usbnet_suspend(intf, message);
-+
-+ /* Disable RX path */
-+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+
-+ /* Force bulk-in zero length */
-+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
-+ 2, 2, &tmp16);
-+
-+ tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
-+ 2, 2, &tmp16);
-+
-+ /* change clock */
-+ tmp8 = 0;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
-+
-+ /* Configure RX control register => stop operation */
-+ tmp16 = AX_RX_CTL_STOP;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
-+
-+ return 0;
-+}
-+
-+/* This function is used to enable the autodetach function. */
-+/* This function is determined by offset 0x43 of EEPROM */
-+static int ax88179_auto_detach(struct usbnet *dev, int in_pm)
-+{
-+ u16 tmp16;
-+ u8 tmp8;
-+ int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *);
-+ int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *);
-+
-+ if (!in_pm) {
-+ fnr = ax88179_read_cmd;
-+ fnw = ax88179_write_cmd;
-+ } else {
-+ fnr = ax88179_read_cmd_nopm;
-+ fnw = ax88179_write_cmd_nopm;
-+ }
-+
-+ if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16) < 0)
-+ return 0;
-+
-+ if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100)))
-+ return 0;
-+
-+ /* Enable Auto Detach bit */
-+ tmp8 = 0;
-+ fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
-+ tmp8 |= AX_CLK_SELECT_ULR;
-+ fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
-+
-+ fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
-+ tmp16 |= AX_PHYPWR_RSTCTL_AT;
-+ fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
-+
-+ return 0;
-+}
-+
-+static int ax88179_resume(struct usb_interface *intf)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ u16 tmp16;
-+ u8 tmp8;
-+
-+ usbnet_link_change(dev, 0, 0);
-+
-+ /* Power up ethernet PHY */
-+ tmp16 = 0;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
-+ 2, 2, &tmp16);
-+ udelay(1000);
-+
-+ tmp16 = AX_PHYPWR_RSTCTL_IPRL;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
-+ 2, 2, &tmp16);
-+ msleep(200);
-+
-+ /* Ethernet PHY Auto Detach*/
-+ ax88179_auto_detach(dev, 1);
-+
-+ /* Enable clock */
-+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
-+ tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
-+ msleep(100);
-+
-+ /* Configure RX control register => start operation */
-+ tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
-+ AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
-+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
-+
-+ return usbnet_resume(intf);
-+}
-+
-+static void
-+ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt;
-+
-+ if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD,
-+ 1, 1, &opt) < 0) {
-+ wolinfo->supported = 0;
-+ wolinfo->wolopts = 0;
-+ return;
-+ }
-+
-+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
-+ wolinfo->wolopts = 0;
-+ if (opt & AX_MONITOR_MODE_RWLC)
-+ wolinfo->wolopts |= WAKE_PHY;
-+ if (opt & AX_MONITOR_MODE_RWMP)
-+ wolinfo->wolopts |= WAKE_MAGIC;
-+}
-+
-+static int
-+ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt = 0;
-+
-+ if (wolinfo->wolopts & WAKE_PHY)
-+ opt |= AX_MONITOR_MODE_RWLC;
-+ if (wolinfo->wolopts & WAKE_MAGIC)
-+ opt |= AX_MONITOR_MODE_RWMP;
-+
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD,
-+ 1, 1, &opt) < 0)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static int ax88179_get_eeprom_len(struct net_device *net)
-+{
-+ return AX_EEPROM_LEN;
-+}
-+
-+static int
-+ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
-+ u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u16 *eeprom_buff;
-+ int first_word, last_word;
-+ int i, ret;
-+
-+ if (eeprom->len == 0)
-+ return -EINVAL;
-+
-+ eeprom->magic = AX88179_EEPROM_MAGIC;
-+
-+ first_word = eeprom->offset >> 1;
-+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
-+ eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
-+ GFP_KERNEL);
-+ if (!eeprom_buff)
-+ return -ENOMEM;
-+
-+ /* ax88179/178A returns 2 bytes from eeprom on read */
-+ for (i = first_word; i <= last_word; i++) {
-+ ret = __ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2,
-+ &eeprom_buff[i - first_word],
-+ 0);
-+ if (ret < 0) {
-+ kfree(eeprom_buff);
-+ return -EIO;
-+ }
-+ }
-+
-+ memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
-+ kfree(eeprom_buff);
-+ return 0;
-+}
-+
-+static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ return mii_ethtool_gset(&dev->mii, cmd);
-+}
-+
-+static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ return mii_ethtool_sset(&dev->mii, cmd);
-+}
-+
-+static int
-+ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data)
-+{
-+ int val;
-+
-+ /* Get Supported EEE */
-+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE,
-+ MDIO_MMD_PCS);
-+ if (val < 0)
-+ return val;
-+ data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
-+
-+ /* Get advertisement EEE */
-+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV,
-+ MDIO_MMD_AN);
-+ if (val < 0)
-+ return val;
-+ data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
-+
-+ /* Get LP advertisement EEE */
-+ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE,
-+ MDIO_MMD_AN);
-+ if (val < 0)
-+ return val;
-+ data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
-+
-+ return 0;
-+}
-+
-+static int
-+ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data)
-+{
-+ u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
-+
-+ return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV,
-+ MDIO_MMD_AN, tmp16);
-+}
-+
-+static int ax88179_chk_eee(struct usbnet *dev)
-+{
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
-+
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+
-+ if (ecmd.duplex & DUPLEX_FULL) {
-+ int eee_lp, eee_cap, eee_adv;
-+ u32 lp, cap, adv, supported = 0;
-+
-+ eee_cap = ax88179_phy_read_mmd_indirect(dev,
-+ MDIO_PCS_EEE_ABLE,
-+ MDIO_MMD_PCS);
-+ if (eee_cap < 0) {
-+ priv->eee_active = 0;
-+ return false;
-+ }
-+
-+ cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
-+ if (!cap) {
-+ priv->eee_active = 0;
-+ return false;
-+ }
-+
-+ eee_lp = ax88179_phy_read_mmd_indirect(dev,
-+ MDIO_AN_EEE_LPABLE,
-+ MDIO_MMD_AN);
-+ if (eee_lp < 0) {
-+ priv->eee_active = 0;
-+ return false;
-+ }
-+
-+ eee_adv = ax88179_phy_read_mmd_indirect(dev,
-+ MDIO_AN_EEE_ADV,
-+ MDIO_MMD_AN);
-+
-+ if (eee_adv < 0) {
-+ priv->eee_active = 0;
-+ return false;
-+ }
-+
-+ adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
-+ lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
-+ supported = (ecmd.speed == SPEED_1000) ?
-+ SUPPORTED_1000baseT_Full :
-+ SUPPORTED_100baseT_Full;
-+
-+ if (!(lp & adv & supported)) {
-+ priv->eee_active = 0;
-+ return false;
-+ }
-+
-+ priv->eee_active = 1;
-+ return true;
-+ }
-+
-+ priv->eee_active = 0;
-+ return false;
-+}
-+
-+static void ax88179_disable_eee(struct usbnet *dev)
-+{
-+ u16 tmp16;
-+
-+ tmp16 = GMII_PHY_PGSEL_PAGE3;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
-+
-+ tmp16 = 0x3246;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_PHYADDR, 2, &tmp16);
-+
-+ tmp16 = GMII_PHY_PGSEL_PAGE0;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
-+}
-+
-+static void ax88179_enable_eee(struct usbnet *dev)
-+{
-+ u16 tmp16;
-+
-+ tmp16 = GMII_PHY_PGSEL_PAGE3;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
-+
-+ tmp16 = 0x3247;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_PHYADDR, 2, &tmp16);
-+
-+ tmp16 = GMII_PHY_PGSEL_PAGE5;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
-+
-+ tmp16 = 0x0680;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ MII_BMSR, 2, &tmp16);
-+
-+ tmp16 = GMII_PHY_PGSEL_PAGE0;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp16);
-+}
-+
-+static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
-+
-+ edata->eee_enabled = priv->eee_enabled;
-+ edata->eee_active = priv->eee_active;
-+
-+ return ax88179_ethtool_get_eee(dev, edata);
-+}
-+
-+static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct ax88179_data *priv = (struct ax88179_data *)dev->data;
-+ int ret = -EOPNOTSUPP;
-+
-+ priv->eee_enabled = edata->eee_enabled;
-+ if (!priv->eee_enabled) {
-+ ax88179_disable_eee(dev);
-+ } else {
-+ priv->eee_enabled = ax88179_chk_eee(dev);
-+ if (!priv->eee_enabled)
-+ return -EOPNOTSUPP;
-+
-+ ax88179_enable_eee(dev);
-+ }
-+
-+ ret = ax88179_ethtool_set_eee(dev, edata);
-+ if (ret)
-+ return ret;
-+
-+ mii_nway_restart(&dev->mii);
-+
-+ usbnet_link_change(dev, 0, 0);
-+
-+ return ret;
-+}
-+
-+static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static const struct ethtool_ops ax88179_ethtool_ops = {
-+ .get_link = ethtool_op_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = ax88179_get_wol,
-+ .set_wol = ax88179_set_wol,
-+ .get_eeprom_len = ax88179_get_eeprom_len,
-+ .get_eeprom = ax88179_get_eeprom,
-+ .get_settings = ax88179_get_settings,
-+ .set_settings = ax88179_set_settings,
-+ .get_eee = ax88179_get_eee,
-+ .set_eee = ax88179_set_eee,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static void ax88179_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct ax88179_data *data = (struct ax88179_data *)dev->data;
-+ u8 *m_filter = ((u8 *)dev->data) + 12;
-+
-+ data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_IPE);
-+
-+ if (net->flags & IFF_PROMISC) {
-+ data->rxctl |= AX_RX_CTL_PRO;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > AX_MAX_MCAST) {
-+ data->rxctl |= AX_RX_CTL_AMALL;
-+ } else if (netdev_mc_empty(net)) {
-+ /* just broadcast and directed */
-+ } else {
-+ /* We use the 20 byte dev->data for our 8 byte filter buffer
-+ * to avoid allocating memory that is tricky to free later
-+ */
-+ u32 crc_bits;
-+ struct netdev_hw_addr *ha;
-+
-+ memset(m_filter, 0, AX_MCAST_FLTSIZE);
-+
-+ netdev_for_each_mc_addr(ha, net) {
-+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ *(m_filter + (crc_bits >> 3)) |= (1 << (crc_bits & 7));
-+ }
-+
-+ ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_MULFLTARY,
-+ AX_MCAST_FLTSIZE, AX_MCAST_FLTSIZE,
-+ m_filter);
-+
-+ data->rxctl |= AX_RX_CTL_AM;
-+ }
-+
-+ ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL,
-+ 2, 2, &data->rxctl);
-+}
-+
-+static int
-+ax88179_set_features(struct net_device *net, netdev_features_t features)
-+{
-+ u8 tmp;
-+ struct usbnet *dev = netdev_priv(net);
-+ netdev_features_t changed = net->features ^ features;
-+
-+ if (changed & NETIF_F_IP_CSUM) {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
-+ tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
-+ }
-+
-+ if (changed & NETIF_F_IPV6_CSUM) {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
-+ tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
-+ }
-+
-+ if (changed & NETIF_F_RXCSUM) {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp);
-+ tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
-+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp);
-+ }
-+
-+ return 0;
-+}
-+
-+static int ax88179_change_mtu(struct net_device *net, int new_mtu)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u16 tmp16;
-+
-+ if (new_mtu <= 0 || new_mtu > 4088)
-+ return -EINVAL;
-+
-+ net->mtu = new_mtu;
-+ dev->hard_mtu = net->mtu + net->hard_header_len;
-+
-+ if (net->mtu > 1500) {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ tmp16 |= AX_MEDIUM_JUMBO_EN;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ } else {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ tmp16 &= ~AX_MEDIUM_JUMBO_EN;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ }
-+
-+ /* max qlen depend on hard_mtu and rx_urb_size */
-+ usbnet_update_max_qlen(dev);
-+
-+ return 0;
-+}
-+
-+static int ax88179_set_mac_addr(struct net_device *net, void *p)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct sockaddr *addr = p;
-+ int ret;
-+
-+ if (netif_running(net))
-+ return -EBUSY;
-+ if (!is_valid_ether_addr(addr->sa_data))
-+ return -EADDRNOTAVAIL;
-+
-+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
-+
-+ /* Set the MAC address */
-+ ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
-+ ETH_ALEN, net->dev_addr);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops ax88179_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = ax88179_change_mtu,
-+ .ndo_set_mac_address = ax88179_set_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = ax88179_ioctl,
-+ .ndo_set_rx_mode = ax88179_set_multicast,
-+ .ndo_set_features = ax88179_set_features,
-+};
-+
-+static int ax88179_check_eeprom(struct usbnet *dev)
-+{
-+ u8 i, buf, eeprom[20];
-+ u16 csum, delay = HZ / 10;
-+ unsigned long jtimeout;
-+
-+ /* Read EEPROM content */
-+ for (i = 0; i < 6; i++) {
-+ buf = i;
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
-+ 1, 1, &buf) < 0)
-+ return -EINVAL;
-+
-+ buf = EEP_RD;
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
-+ 1, 1, &buf) < 0)
-+ return -EINVAL;
-+
-+ jtimeout = jiffies + delay;
-+ do {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
-+ 1, 1, &buf);
-+
-+ if (time_after(jiffies, jtimeout))
-+ return -EINVAL;
-+
-+ } while (buf & EEP_BUSY);
-+
-+ __ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
-+ 2, 2, &eeprom[i * 2], 0);
-+
-+ if ((i == 0) && (eeprom[0] == 0xFF))
-+ return -EINVAL;
-+ }
-+
-+ csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9];
-+ csum = (csum >> 8) + (csum & 0xff);
-+ if ((csum + eeprom[10]) != 0xff)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static int ax88179_check_efuse(struct usbnet *dev, u16 *ledmode)
-+{
-+ u8 i;
-+ u8 efuse[64];
-+ u16 csum = 0;
-+
-+ if (ax88179_read_cmd(dev, AX_ACCESS_EFUS, 0, 64, 64, efuse) < 0)
-+ return -EINVAL;
-+
-+ if (*efuse == 0xFF)
-+ return -EINVAL;
-+
-+ for (i = 0; i < 64; i++)
-+ csum = csum + efuse[i];
-+
-+ while (csum > 255)
-+ csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF);
-+
-+ if (csum != 0xFF)
-+ return -EINVAL;
-+
-+ *ledmode = (efuse[51] << 8) | efuse[52];
-+
-+ return 0;
-+}
-+
-+static int ax88179_convert_old_led(struct usbnet *dev, u16 *ledvalue)
-+{
-+ u16 led;
-+
-+ /* Loaded the old eFuse LED Mode */
-+ if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C, 1, 2, &led) < 0)
-+ return -EINVAL;
-+
-+ led >>= 8;
-+ switch (led) {
-+ case 0xFF:
-+ led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
-+ LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
-+ LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
-+ break;
-+ case 0xFE:
-+ led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID;
-+ break;
-+ case 0xFD:
-+ led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 |
-+ LED2_LINK_10 | LED_VALID;
-+ break;
-+ case 0xFC:
-+ led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE |
-+ LED2_LINK_100 | LED2_LINK_10 | LED_VALID;
-+ break;
-+ default:
-+ led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
-+ LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
-+ LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
-+ break;
-+ }
-+
-+ *ledvalue = led;
-+
-+ return 0;
-+}
-+
-+static int ax88179_led_setting(struct usbnet *dev)
-+{
-+ u8 ledfd, value = 0;
-+ u16 tmp, ledact, ledlink, ledvalue = 0, delay = HZ / 10;
-+ unsigned long jtimeout;
-+
-+ /* Check AX88179 version. UA1 or UA2*/
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value);
-+
-+ if (!(value & AX_SECLD)) { /* UA1 */
-+ value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN |
-+ AX_GPIO_CTRL_GPIO1EN;
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL,
-+ 1, 1, &value) < 0)
-+ return -EINVAL;
-+ }
-+
-+ /* Check EEPROM */
-+ if (!ax88179_check_eeprom(dev)) {
-+ value = 0x42;
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
-+ 1, 1, &value) < 0)
-+ return -EINVAL;
-+
-+ value = EEP_RD;
-+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
-+ 1, 1, &value) < 0)
-+ return -EINVAL;
-+
-+ jtimeout = jiffies + delay;
-+ do {
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
-+ 1, 1, &value);
-+
-+ if (time_after(jiffies, jtimeout))
-+ return -EINVAL;
-+
-+ } while (value & EEP_BUSY);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH,
-+ 1, 1, &value);
-+ ledvalue = (value << 8);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
-+ 1, 1, &value);
-+ ledvalue |= value;
-+
-+ /* load internal ROM for defaule setting */
-+ if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
-+ ax88179_convert_old_led(dev, &ledvalue);
-+
-+ } else if (!ax88179_check_efuse(dev, &ledvalue)) {
-+ if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
-+ ax88179_convert_old_led(dev, &ledvalue);
-+ } else {
-+ ax88179_convert_old_led(dev, &ledvalue);
-+ }
-+
-+ tmp = GMII_PHY_PGSEL_EXT;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp);
-+
-+ tmp = 0x2c;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHYPAGE, 2, &tmp);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_LED_ACT, 2, &ledact);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_LED_LINK, 2, &ledlink);
-+
-+ ledact &= GMII_LED_ACTIVE_MASK;
-+ ledlink &= GMII_LED_LINK_MASK;
-+
-+ if (ledvalue & LED0_ACTIVE)
-+ ledact |= GMII_LED0_ACTIVE;
-+
-+ if (ledvalue & LED1_ACTIVE)
-+ ledact |= GMII_LED1_ACTIVE;
-+
-+ if (ledvalue & LED2_ACTIVE)
-+ ledact |= GMII_LED2_ACTIVE;
-+
-+ if (ledvalue & LED0_LINK_10)
-+ ledlink |= GMII_LED0_LINK_10;
-+
-+ if (ledvalue & LED1_LINK_10)
-+ ledlink |= GMII_LED1_LINK_10;
-+
-+ if (ledvalue & LED2_LINK_10)
-+ ledlink |= GMII_LED2_LINK_10;
-+
-+ if (ledvalue & LED0_LINK_100)
-+ ledlink |= GMII_LED0_LINK_100;
-+
-+ if (ledvalue & LED1_LINK_100)
-+ ledlink |= GMII_LED1_LINK_100;
-+
-+ if (ledvalue & LED2_LINK_100)
-+ ledlink |= GMII_LED2_LINK_100;
-+
-+ if (ledvalue & LED0_LINK_1000)
-+ ledlink |= GMII_LED0_LINK_1000;
-+
-+ if (ledvalue & LED1_LINK_1000)
-+ ledlink |= GMII_LED1_LINK_1000;
-+
-+ if (ledvalue & LED2_LINK_1000)
-+ ledlink |= GMII_LED2_LINK_1000;
-+
-+ tmp = ledact;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_LED_ACT, 2, &tmp);
-+
-+ tmp = ledlink;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_LED_LINK, 2, &tmp);
-+
-+ tmp = GMII_PHY_PGSEL_PAGE0;
-+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PAGE_SELECT, 2, &tmp);
-+
-+ /* LED full duplex setting */
-+ ledfd = 0;
-+ if (ledvalue & LED0_FD)
-+ ledfd |= 0x01;
-+ else if ((ledvalue & LED0_USB3_MASK) == 0)
-+ ledfd |= 0x02;
-+
-+ if (ledvalue & LED1_FD)
-+ ledfd |= 0x04;
-+ else if ((ledvalue & LED1_USB3_MASK) == 0)
-+ ledfd |= 0x08;
-+
-+ if (ledvalue & LED2_FD)
-+ ledfd |= 0x10;
-+ else if ((ledvalue & LED2_USB3_MASK) == 0)
-+ ledfd |= 0x20;
-+
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_LEDCTRL, 1, 1, &ledfd);
-+
-+ return 0;
-+}
-+
-+static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ u8 buf[5];
-+ u16 *tmp16;
-+ u8 *tmp;
-+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
-+ struct ethtool_eee eee_data;
-+
-+ usbnet_get_endpoints(dev, intf);
-+
-+ tmp16 = (u16 *)buf;
-+ tmp = (u8 *)buf;
-+
-+ memset(ax179_data, 0, sizeof(*ax179_data));
-+
-+ /* Power up ethernet PHY */
-+ *tmp16 = 0;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
-+ *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
-+ msleep(200);
-+
-+ *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
-+ msleep(100);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
-+ ETH_ALEN, dev->net->dev_addr);
-+ memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
-+
-+ /* RX bulk configuration */
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
-+
-+ dev->rx_urb_size = 1024 * 20;
-+
-+ *tmp = 0x34;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
-+
-+ *tmp = 0x52;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
-+ 1, 1, tmp);
-+
-+ dev->net->netdev_ops = &ax88179_netdev_ops;
-+ dev->net->ethtool_ops = &ax88179_ethtool_ops;
-+ dev->net->needed_headroom = 8;
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = ax88179_mdio_read;
-+ dev->mii.mdio_write = ax88179_mdio_write;
-+ dev->mii.phy_id_mask = 0xff;
-+ dev->mii.reg_num_mask = 0xff;
-+ dev->mii.phy_id = 0x03;
-+ dev->mii.supports_gmii = 1;
-+
-+ dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+
-+ dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+
-+ /* Enable checksum offload */
-+ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
-+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
-+
-+ *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
-+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
-+
-+ /* Configure RX control register => start operation */
-+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
-+ AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
-+
-+ *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
-+ AX_MONITOR_MODE_RWMP;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp);
-+
-+ /* Configure default medium type => giga */
-+ *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
-+ AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
-+ AX_MEDIUM_GIGAMODE;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, tmp16);
-+
-+ ax88179_led_setting(dev);
-+
-+ ax179_data->eee_enabled = 0;
-+ ax179_data->eee_active = 0;
-+
-+ ax88179_disable_eee(dev);
-+
-+ ax88179_ethtool_get_eee(dev, &eee_data);
-+ eee_data.advertised = 0;
-+ ax88179_ethtool_set_eee(dev, &eee_data);
-+
-+ /* Restart autoneg */
-+ mii_nway_restart(&dev->mii);
-+
-+ usbnet_link_change(dev, 0, 0);
-+
-+ return 0;
-+}
-+
-+static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ u16 tmp16;
-+
-+ /* Configure RX control register => stop operation */
-+ tmp16 = AX_RX_CTL_STOP;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
-+
-+ tmp16 = 0;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp16);
-+
-+ /* Power down ethernet PHY */
-+ tmp16 = 0;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
-+}
-+
-+static void
-+ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr)
-+{
-+ skb->ip_summed = CHECKSUM_NONE;
-+
-+ /* checksum error bit is set */
-+ if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) ||
-+ (*pkt_hdr & AX_RXHDR_L4CSUM_ERR))
-+ return;
-+
-+ /* It must be a TCP or UDP packet with a valid checksum */
-+ if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) ||
-+ ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP))
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+}
-+
-+static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct sk_buff *ax_skb;
-+ int pkt_cnt;
-+ u32 rx_hdr;
-+ u16 hdr_off;
-+ u32 *pkt_hdr;
-+
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ skb_trim(skb, skb->len - 4);
-+ memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
-+ le32_to_cpus(&rx_hdr);
-+
-+ pkt_cnt = (u16)rx_hdr;
-+ hdr_off = (u16)(rx_hdr >> 16);
-+ pkt_hdr = (u32 *)(skb->data + hdr_off);
-+
-+ while (pkt_cnt--) {
-+ u16 pkt_len;
-+
-+ le32_to_cpus(pkt_hdr);
-+ pkt_len = (*pkt_hdr >> 16) & 0x1fff;
-+
-+ /* Check CRC or runt packet */
-+ if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
-+ (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
-+ skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-+ pkt_hdr++;
-+ continue;
-+ }
-+
-+ if (pkt_cnt == 0) {
-+ /* Skip IP alignment psudo header */
-+ skb_pull(skb, 2);
-+ skb->len = pkt_len;
-+ skb_set_tail_pointer(skb, pkt_len);
-+ skb->truesize = pkt_len + sizeof(struct sk_buff);
-+ ax88179_rx_checksum(skb, pkt_hdr);
-+ return 1;
-+ }
-+
-+ ax_skb = skb_clone(skb, GFP_ATOMIC);
-+ if (ax_skb) {
-+ ax_skb->len = pkt_len;
-+ ax_skb->data = skb->data + 2;
-+ skb_set_tail_pointer(ax_skb, pkt_len);
-+ ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
-+ ax88179_rx_checksum(ax_skb, pkt_hdr);
-+ usbnet_skb_return(dev, ax_skb);
-+ } else {
-+ return 0;
-+ }
-+
-+ skb_pull(skb, (pkt_len + 7) & 0xFFF8);
-+ pkt_hdr++;
-+ }
-+ return 1;
-+}
-+
-+static struct sk_buff *
-+ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
-+{
-+ u32 tx_hdr1, tx_hdr2;
-+ int frame_size = dev->maxpacket;
-+ int mss = skb_shinfo(skb)->gso_size;
-+ int headroom;
-+
-+ tx_hdr1 = skb->len;
-+ tx_hdr2 = mss;
-+ if (((skb->len + 8) % frame_size) == 0)
-+ tx_hdr2 |= 0x80008000; /* Enable padding */
-+
-+ headroom = skb_headroom(skb) - 8;
-+
-+ if ((skb_header_cloned(skb) || headroom < 0) &&
-+ pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) {
-+ dev_kfree_skb_any(skb);
-+ return NULL;
-+ }
-+
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&tx_hdr2);
-+ skb_copy_to_linear_data(skb, &tx_hdr2, 4);
-+
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&tx_hdr1);
-+ skb_copy_to_linear_data(skb, &tx_hdr1, 4);
-+
-+ return skb;
-+}
-+
-+static int ax88179_link_reset(struct usbnet *dev)
-+{
-+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
-+ u8 tmp[5], link_sts;
-+ u16 mode, tmp16, delay = HZ / 10;
-+ u32 tmp32 = 0x40000000;
-+ unsigned long jtimeout;
-+
-+ jtimeout = jiffies + delay;
-+ while (tmp32 & 0x40000000) {
-+ mode = 0;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode);
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2,
-+ &ax179_data->rxctl);
-+
-+ /*link up, check the usb device control TX FIFO full or empty*/
-+ ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32);
-+
-+ if (time_after(jiffies, jtimeout))
-+ return 0;
-+ }
-+
-+ mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
-+ AX_MEDIUM_RXFLOW_CTRLEN;
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS,
-+ 1, 1, &link_sts);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
-+ GMII_PHY_PHYSR, 2, &tmp16);
-+
-+ if (!(tmp16 & GMII_PHY_PHYSR_LINK)) {
-+ return 0;
-+ } else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
-+ mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ;
-+ if (dev->net->mtu > 1500)
-+ mode |= AX_MEDIUM_JUMBO_EN;
-+
-+ if (link_sts & AX_USB_SS)
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
-+ else if (link_sts & AX_USB_HS)
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
-+ else
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
-+ } else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
-+ mode |= AX_MEDIUM_PS;
-+
-+ if (link_sts & (AX_USB_SS | AX_USB_HS))
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
-+ else
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
-+ } else {
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
-+ }
-+
-+ /* RX bulk configuration */
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
-+
-+ dev->rx_urb_size = (1024 * (tmp[3] + 2));
-+
-+ if (tmp16 & GMII_PHY_PHYSR_FULL)
-+ mode |= AX_MEDIUM_FULL_DUPLEX;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &mode);
-+
-+ ax179_data->eee_enabled = ax88179_chk_eee(dev);
-+
-+ netif_carrier_on(dev->net);
-+
-+ return 0;
-+}
-+
-+static int ax88179_reset(struct usbnet *dev)
-+{
-+ u8 buf[5];
-+ u16 *tmp16;
-+ u8 *tmp;
-+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
-+ struct ethtool_eee eee_data;
-+
-+ tmp16 = (u16 *)buf;
-+ tmp = (u8 *)buf;
-+
-+ /* Power up ethernet PHY */
-+ *tmp16 = 0;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
-+
-+ *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
-+ msleep(200);
-+
-+ *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
-+ msleep(100);
-+
-+ /* Ethernet PHY Auto Detach*/
-+ ax88179_auto_detach(dev, 0);
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN,
-+ dev->net->dev_addr);
-+ memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
-+
-+ /* RX bulk configuration */
-+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
-+
-+ dev->rx_urb_size = 1024 * 20;
-+
-+ *tmp = 0x34;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
-+
-+ *tmp = 0x52;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
-+ 1, 1, tmp);
-+
-+ dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+
-+ dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+
-+ /* Enable checksum offload */
-+ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
-+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
-+
-+ *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
-+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
-+
-+ /* Configure RX control register => start operation */
-+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START |
-+ AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
-+
-+ *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
-+ AX_MONITOR_MODE_RWMP;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp);
-+
-+ /* Configure default medium type => giga */
-+ *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
-+ AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
-+ AX_MEDIUM_GIGAMODE;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, tmp16);
-+
-+ ax88179_led_setting(dev);
-+
-+ ax179_data->eee_enabled = 0;
-+ ax179_data->eee_active = 0;
-+
-+ ax88179_disable_eee(dev);
-+
-+ ax88179_ethtool_get_eee(dev, &eee_data);
-+ eee_data.advertised = 0;
-+ ax88179_ethtool_set_eee(dev, &eee_data);
-+
-+ /* Restart autoneg */
-+ mii_nway_restart(&dev->mii);
-+
-+ usbnet_link_change(dev, 0, 0);
-+
-+ return 0;
-+}
-+
-+static int ax88179_stop(struct usbnet *dev)
-+{
-+ u16 tmp16;
-+
-+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+ tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
-+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
-+ 2, 2, &tmp16);
-+
-+ return 0;
-+}
-+
-+static const struct driver_info ax88179_info = {
-+ .description = "ASIX AX88179 USB 3.0 Gigabit Ethernet",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct driver_info ax88178a_info = {
-+ .description = "ASIX AX88178A USB 2.0 Gigabit Ethernet",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct driver_info dlink_dub1312_info = {
-+ .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct driver_info sitecom_info = {
-+ .description = "Sitecom USB 3.0 to Gigabit Adapter",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct driver_info samsung_info = {
-+ .description = "Samsung USB Ethernet Adapter",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct driver_info lenovo_info = {
-+ .description = "Lenovo OneLinkDock Gigabit LAN",
-+ .bind = ax88179_bind,
-+ .unbind = ax88179_unbind,
-+ .status = ax88179_status,
-+ .link_reset = ax88179_link_reset,
-+ .reset = ax88179_reset,
-+ .stop = ax88179_stop,
-+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
-+ .rx_fixup = ax88179_rx_fixup,
-+ .tx_fixup = ax88179_tx_fixup,
-+};
-+
-+static const struct usb_device_id products[] = {
-+{
-+ /* ASIX AX88179 10/100/1000 */
-+ USB_DEVICE(0x0b95, 0x1790),
-+ .driver_info = (unsigned long)&ax88179_info,
-+}, {
-+ /* ASIX AX88178A 10/100/1000 */
-+ USB_DEVICE(0x0b95, 0x178a),
-+ .driver_info = (unsigned long)&ax88178a_info,
-+}, {
-+ /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
-+ USB_DEVICE(0x2001, 0x4a00),
-+ .driver_info = (unsigned long)&dlink_dub1312_info,
-+}, {
-+ /* Sitecom USB 3.0 to Gigabit Adapter */
-+ USB_DEVICE(0x0df6, 0x0072),
-+ .driver_info = (unsigned long)&sitecom_info,
-+}, {
-+ /* Samsung USB Ethernet Adapter */
-+ USB_DEVICE(0x04e8, 0xa100),
-+ .driver_info = (unsigned long)&samsung_info,
-+}, {
-+ /* Lenovo OneLinkDock Gigabit LAN */
-+ USB_DEVICE(0x17ef, 0x304b),
-+ .driver_info = (unsigned long)&lenovo_info,
-+},
-+ { },
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver ax88179_178a_driver = {
-+ .name = "ax88179_178a",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .suspend = ax88179_suspend,
-+ .resume = ax88179_resume,
-+ .reset_resume = ax88179_resume,
-+ .disconnect = usbnet_disconnect,
-+ .supports_autosuspend = 1,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(ax88179_178a_driver);
-+
-+MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/catc.c backports-4.2.6-1/drivers/net/usb/catc.c
---- backports-4.2.6-1.org/drivers/net/usb/catc.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/catc.c 2016-06-28 14:35:17.975307221 +0200
-@@ -0,0 +1,965 @@
-+/*
-+ * Copyright (c) 2001 Vojtech Pavlik
-+ *
-+ * CATC EL1210A NetMate USB Ethernet driver
-+ *
-+ * Sponsored by SuSE
-+ *
-+ * Based on the work of
-+ * Donald Becker
-+ *
-+ * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002
-+ * - adds support for Belkin F5U011
-+ */
-+
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ * Should you need to contact me, the author, you can do so either by
-+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
-+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/spinlock.h>
-+#include <linux/ethtool.h>
-+#include <linux/crc32.h>
-+#include <linux/bitops.h>
-+#include <linux/gfp.h>
-+#include <asm/uaccess.h>
-+
-+#undef DEBUG
-+
-+#include <linux/usb.h>
-+
-+/*
-+ * Version information.
-+ */
-+
-+#define DRIVER_VERSION "v2.8"
-+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>"
-+#define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver"
-+#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet"
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_LICENSE("GPL");
-+
-+static const char driver_name[] = "catc";
-+
-+/*
-+ * Some defines.
-+ */
-+
-+#define STATS_UPDATE (HZ) /* Time between stats updates */
-+#define TX_TIMEOUT (5*HZ) /* Max time the queue can be stopped */
-+#define PKT_SZ 1536 /* Max Ethernet packet size */
-+#define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */
-+#define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */
-+#define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */
-+#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */
-+
-+/*
-+ * Control requests.
-+ */
-+
-+enum control_requests {
-+ ReadMem = 0xf1,
-+ GetMac = 0xf2,
-+ Reset = 0xf4,
-+ SetMac = 0xf5,
-+ SetRxMode = 0xf5, /* F5U011 only */
-+ WriteROM = 0xf8,
-+ SetReg = 0xfa,
-+ GetReg = 0xfb,
-+ WriteMem = 0xfc,
-+ ReadROM = 0xfd,
-+};
-+
-+/*
-+ * Registers.
-+ */
-+
-+enum register_offsets {
-+ TxBufCount = 0x20,
-+ RxBufCount = 0x21,
-+ OpModes = 0x22,
-+ TxQed = 0x23,
-+ RxQed = 0x24,
-+ MaxBurst = 0x25,
-+ RxUnit = 0x60,
-+ EthStatus = 0x61,
-+ StationAddr0 = 0x67,
-+ EthStats = 0x69,
-+ LEDCtrl = 0x81,
-+};
-+
-+enum eth_stats {
-+ TxSingleColl = 0x00,
-+ TxMultiColl = 0x02,
-+ TxExcessColl = 0x04,
-+ RxFramErr = 0x06,
-+};
-+
-+enum op_mode_bits {
-+ Op3MemWaits = 0x03,
-+ OpLenInclude = 0x08,
-+ OpRxMerge = 0x10,
-+ OpTxMerge = 0x20,
-+ OpWin95bugfix = 0x40,
-+ OpLoopback = 0x80,
-+};
-+
-+enum rx_filter_bits {
-+ RxEnable = 0x01,
-+ RxPolarity = 0x02,
-+ RxForceOK = 0x04,
-+ RxMultiCast = 0x08,
-+ RxPromisc = 0x10,
-+ AltRxPromisc = 0x20, /* F5U011 uses different bit */
-+};
-+
-+enum led_values {
-+ LEDFast = 0x01,
-+ LEDSlow = 0x02,
-+ LEDFlash = 0x03,
-+ LEDPulse = 0x04,
-+ LEDLink = 0x08,
-+};
-+
-+enum link_status {
-+ LinkNoChange = 0,
-+ LinkGood = 1,
-+ LinkBad = 2
-+};
-+
-+/*
-+ * The catc struct.
-+ */
-+
-+#define CTRL_RUNNING 0
-+#define RX_RUNNING 1
-+#define TX_RUNNING 2
-+
-+struct catc {
-+ struct net_device *netdev;
-+ struct usb_device *usbdev;
-+
-+ unsigned long flags;
-+
-+ unsigned int tx_ptr, tx_idx;
-+ unsigned int ctrl_head, ctrl_tail;
-+ spinlock_t tx_lock, ctrl_lock;
-+
-+ u8 tx_buf[2][TX_MAX_BURST * (PKT_SZ + 2)];
-+ u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)];
-+ u8 irq_buf[2];
-+ u8 ctrl_buf[64];
-+ struct usb_ctrlrequest ctrl_dr;
-+
-+ struct timer_list timer;
-+ u8 stats_buf[8];
-+ u16 stats_vals[4];
-+ unsigned long last_stats;
-+
-+ u8 multicast[64];
-+
-+ struct ctrl_queue {
-+ u8 dir;
-+ u8 request;
-+ u16 value;
-+ u16 index;
-+ void *buf;
-+ int len;
-+ void (*callback)(struct catc *catc, struct ctrl_queue *q);
-+ } ctrl_queue[CTRL_QUEUE];
-+
-+ struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
-+
-+ u8 is_f5u011; /* Set if device is an F5U011 */
-+ u8 rxmode[2]; /* Used for F5U011 */
-+ atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */
-+};
-+
-+/*
-+ * Useful macros.
-+ */
-+
-+#define catc_get_mac(catc, mac) catc_ctrl_msg(catc, USB_DIR_IN, GetMac, 0, 0, mac, 6)
-+#define catc_reset(catc) catc_ctrl_msg(catc, USB_DIR_OUT, Reset, 0, 0, NULL, 0)
-+#define catc_set_reg(catc, reg, val) catc_ctrl_msg(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0)
-+#define catc_get_reg(catc, reg, buf) catc_ctrl_msg(catc, USB_DIR_IN, GetReg, 0, reg, buf, 1)
-+#define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size)
-+#define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size)
-+
-+#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2)
-+#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL)
-+#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL)
-+
-+#define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL)
-+#define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb)
-+#define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL)
-+
-+/*
-+ * Receive routines.
-+ */
-+
-+static void catc_rx_done(struct urb *urb)
-+{
-+ struct catc *catc = urb->context;
-+ u8 *pkt_start = urb->transfer_buffer;
-+ struct sk_buff *skb;
-+ int pkt_len, pkt_offset = 0;
-+ int status = urb->status;
-+
-+ if (!catc->is_f5u011) {
-+ clear_bit(RX_RUNNING, &catc->flags);
-+ pkt_offset = 2;
-+ }
-+
-+ if (status) {
-+ dev_dbg(&urb->dev->dev, "rx_done, status %d, length %d\n",
-+ status, urb->actual_length);
-+ return;
-+ }
-+
-+ do {
-+ if(!catc->is_f5u011) {
-+ pkt_len = le16_to_cpup((__le16*)pkt_start);
-+ if (pkt_len > urb->actual_length) {
-+ catc->netdev->stats.rx_length_errors++;
-+ catc->netdev->stats.rx_errors++;
-+ break;
-+ }
-+ } else {
-+ pkt_len = urb->actual_length;
-+ }
-+
-+ if (!(skb = dev_alloc_skb(pkt_len)))
-+ return;
-+
-+ skb_copy_to_linear_data(skb, pkt_start + pkt_offset, pkt_len);
-+ skb_put(skb, pkt_len);
-+
-+ skb->protocol = eth_type_trans(skb, catc->netdev);
-+ netif_rx(skb);
-+
-+ catc->netdev->stats.rx_packets++;
-+ catc->netdev->stats.rx_bytes += pkt_len;
-+
-+ /* F5U011 only does one packet per RX */
-+ if (catc->is_f5u011)
-+ break;
-+ pkt_start += (((pkt_len + 1) >> 6) + 1) << 6;
-+
-+ } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length);
-+
-+ if (catc->is_f5u011) {
-+ if (atomic_read(&catc->recq_sz)) {
-+ int state;
-+ atomic_dec(&catc->recq_sz);
-+ netdev_dbg(catc->netdev, "getting extra packet\n");
-+ urb->dev = catc->usbdev;
-+ if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
-+ netdev_dbg(catc->netdev,
-+ "submit(rx_urb) status %d\n", state);
-+ }
-+ } else {
-+ clear_bit(RX_RUNNING, &catc->flags);
-+ }
-+ }
-+}
-+
-+static void catc_irq_done(struct urb *urb)
-+{
-+ struct catc *catc = urb->context;
-+ u8 *data = urb->transfer_buffer;
-+ int status = urb->status;
-+ unsigned int hasdata = 0, linksts = LinkNoChange;
-+ int res;
-+
-+ if (!catc->is_f5u011) {
-+ hasdata = data[1] & 0x80;
-+ if (data[1] & 0x40)
-+ linksts = LinkGood;
-+ else if (data[1] & 0x20)
-+ linksts = LinkBad;
-+ } else {
-+ hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff);
-+ if (data[0] == 0x90)
-+ linksts = LinkGood;
-+ else if (data[0] == 0xA0)
-+ linksts = LinkBad;
-+ }
-+
-+ switch (status) {
-+ case 0: /* success */
-+ break;
-+ case -ECONNRESET: /* unlink */
-+ case -ENOENT:
-+ case -ESHUTDOWN:
-+ return;
-+ /* -EPIPE: should clear the halt */
-+ default: /* error */
-+ dev_dbg(&urb->dev->dev,
-+ "irq_done, status %d, data %02x %02x.\n",
-+ status, data[0], data[1]);
-+ goto resubmit;
-+ }
-+
-+ if (linksts == LinkGood) {
-+ netif_carrier_on(catc->netdev);
-+ netdev_dbg(catc->netdev, "link ok\n");
-+ }
-+
-+ if (linksts == LinkBad) {
-+ netif_carrier_off(catc->netdev);
-+ netdev_dbg(catc->netdev, "link bad\n");
-+ }
-+
-+ if (hasdata) {
-+ if (test_and_set_bit(RX_RUNNING, &catc->flags)) {
-+ if (catc->is_f5u011)
-+ atomic_inc(&catc->recq_sz);
-+ } else {
-+ catc->rx_urb->dev = catc->usbdev;
-+ if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
-+ dev_err(&catc->usbdev->dev,
-+ "submit(rx_urb) status %d\n", res);
-+ }
-+ }
-+ }
-+resubmit:
-+ res = usb_submit_urb (urb, GFP_ATOMIC);
-+ if (res)
-+ dev_err(&catc->usbdev->dev,
-+ "can't resubmit intr, %s-%s, status %d\n",
-+ catc->usbdev->bus->bus_name,
-+ catc->usbdev->devpath, res);
-+}
-+
-+/*
-+ * Transmit routines.
-+ */
-+
-+static int catc_tx_run(struct catc *catc)
-+{
-+ int status;
-+
-+ if (catc->is_f5u011)
-+ catc->tx_ptr = (catc->tx_ptr + 63) & ~63;
-+
-+ catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
-+ catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
-+ catc->tx_urb->dev = catc->usbdev;
-+
-+ if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
-+ dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n",
-+ status);
-+
-+ catc->tx_idx = !catc->tx_idx;
-+ catc->tx_ptr = 0;
-+
-+ catc->netdev->trans_start = jiffies;
-+ return status;
-+}
-+
-+static void catc_tx_done(struct urb *urb)
-+{
-+ struct catc *catc = urb->context;
-+ unsigned long flags;
-+ int r, status = urb->status;
-+
-+ if (status == -ECONNRESET) {
-+ dev_dbg(&urb->dev->dev, "Tx Reset.\n");
-+ urb->status = 0;
-+ catc->netdev->trans_start = jiffies;
-+ catc->netdev->stats.tx_errors++;
-+ clear_bit(TX_RUNNING, &catc->flags);
-+ netif_wake_queue(catc->netdev);
-+ return;
-+ }
-+
-+ if (status) {
-+ dev_dbg(&urb->dev->dev, "tx_done, status %d, length %d\n",
-+ status, urb->actual_length);
-+ return;
-+ }
-+
-+ spin_lock_irqsave(&catc->tx_lock, flags);
-+
-+ if (catc->tx_ptr) {
-+ r = catc_tx_run(catc);
-+ if (unlikely(r < 0))
-+ clear_bit(TX_RUNNING, &catc->flags);
-+ } else {
-+ clear_bit(TX_RUNNING, &catc->flags);
-+ }
-+
-+ netif_wake_queue(catc->netdev);
-+
-+ spin_unlock_irqrestore(&catc->tx_lock, flags);
-+}
-+
-+static netdev_tx_t catc_start_xmit(struct sk_buff *skb,
-+ struct net_device *netdev)
-+{
-+ struct catc *catc = netdev_priv(netdev);
-+ unsigned long flags;
-+ int r = 0;
-+ char *tx_buf;
-+
-+ spin_lock_irqsave(&catc->tx_lock, flags);
-+
-+ catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
-+ tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
-+ if (catc->is_f5u011)
-+ *(__be16 *)tx_buf = cpu_to_be16(skb->len);
-+ else
-+ *(__le16 *)tx_buf = cpu_to_le16(skb->len);
-+ skb_copy_from_linear_data(skb, tx_buf + 2, skb->len);
-+ catc->tx_ptr += skb->len + 2;
-+
-+ if (!test_and_set_bit(TX_RUNNING, &catc->flags)) {
-+ r = catc_tx_run(catc);
-+ if (r < 0)
-+ clear_bit(TX_RUNNING, &catc->flags);
-+ }
-+
-+ if ((catc->is_f5u011 && catc->tx_ptr) ||
-+ (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))))
-+ netif_stop_queue(netdev);
-+
-+ spin_unlock_irqrestore(&catc->tx_lock, flags);
-+
-+ if (r >= 0) {
-+ catc->netdev->stats.tx_bytes += skb->len;
-+ catc->netdev->stats.tx_packets++;
-+ }
-+
-+ dev_kfree_skb(skb);
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+static void catc_tx_timeout(struct net_device *netdev)
-+{
-+ struct catc *catc = netdev_priv(netdev);
-+
-+ dev_warn(&netdev->dev, "Transmit timed out.\n");
-+ usb_unlink_urb(catc->tx_urb);
-+}
-+
-+/*
-+ * Control messages.
-+ */
-+
-+static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
-+{
-+ int retval = usb_control_msg(catc->usbdev,
-+ dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0),
-+ request, 0x40 | dir, value, index, buf, len, 1000);
-+ return retval < 0 ? retval : 0;
-+}
-+
-+static void catc_ctrl_run(struct catc *catc)
-+{
-+ struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
-+ struct usb_device *usbdev = catc->usbdev;
-+ struct urb *urb = catc->ctrl_urb;
-+ struct usb_ctrlrequest *dr = &catc->ctrl_dr;
-+ int status;
-+
-+ dr->bRequest = q->request;
-+ dr->bRequestType = 0x40 | q->dir;
-+ dr->wValue = cpu_to_le16(q->value);
-+ dr->wIndex = cpu_to_le16(q->index);
-+ dr->wLength = cpu_to_le16(q->len);
-+
-+ urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0);
-+ urb->transfer_buffer_length = q->len;
-+ urb->transfer_buffer = catc->ctrl_buf;
-+ urb->setup_packet = (void *) dr;
-+ urb->dev = usbdev;
-+
-+ if (!q->dir && q->buf && q->len)
-+ memcpy(catc->ctrl_buf, q->buf, q->len);
-+
-+ if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
-+ dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n",
-+ status);
-+}
-+
-+static void catc_ctrl_done(struct urb *urb)
-+{
-+ struct catc *catc = urb->context;
-+ struct ctrl_queue *q;
-+ unsigned long flags;
-+ int status = urb->status;
-+
-+ if (status)
-+ dev_dbg(&urb->dev->dev, "ctrl_done, status %d, len %d.\n",
-+ status, urb->actual_length);
-+
-+ spin_lock_irqsave(&catc->ctrl_lock, flags);
-+
-+ q = catc->ctrl_queue + catc->ctrl_tail;
-+
-+ if (q->dir) {
-+ if (q->buf && q->len)
-+ memcpy(q->buf, catc->ctrl_buf, q->len);
-+ else
-+ q->buf = catc->ctrl_buf;
-+ }
-+
-+ if (q->callback)
-+ q->callback(catc, q);
-+
-+ catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
-+
-+ if (catc->ctrl_head != catc->ctrl_tail)
-+ catc_ctrl_run(catc);
-+ else
-+ clear_bit(CTRL_RUNNING, &catc->flags);
-+
-+ spin_unlock_irqrestore(&catc->ctrl_lock, flags);
-+}
-+
-+static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,
-+ u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q))
-+{
-+ struct ctrl_queue *q;
-+ int retval = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&catc->ctrl_lock, flags);
-+
-+ q = catc->ctrl_queue + catc->ctrl_head;
-+
-+ q->dir = dir;
-+ q->request = request;
-+ q->value = value;
-+ q->index = index;
-+ q->buf = buf;
-+ q->len = len;
-+ q->callback = callback;
-+
-+ catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);
-+
-+ if (catc->ctrl_head == catc->ctrl_tail) {
-+ dev_err(&catc->usbdev->dev, "ctrl queue full\n");
-+ catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
-+ retval = -1;
-+ }
-+
-+ if (!test_and_set_bit(CTRL_RUNNING, &catc->flags))
-+ catc_ctrl_run(catc);
-+
-+ spin_unlock_irqrestore(&catc->ctrl_lock, flags);
-+
-+ return retval;
-+}
-+
-+/*
-+ * Statistics.
-+ */
-+
-+static void catc_stats_done(struct catc *catc, struct ctrl_queue *q)
-+{
-+ int index = q->index - EthStats;
-+ u16 data, last;
-+
-+ catc->stats_buf[index] = *((char *)q->buf);
-+
-+ if (index & 1)
-+ return;
-+
-+ data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1];
-+ last = catc->stats_vals[index >> 1];
-+
-+ switch (index) {
-+ case TxSingleColl:
-+ case TxMultiColl:
-+ catc->netdev->stats.collisions += data - last;
-+ break;
-+ case TxExcessColl:
-+ catc->netdev->stats.tx_aborted_errors += data - last;
-+ catc->netdev->stats.tx_errors += data - last;
-+ break;
-+ case RxFramErr:
-+ catc->netdev->stats.rx_frame_errors += data - last;
-+ catc->netdev->stats.rx_errors += data - last;
-+ break;
-+ }
-+
-+ catc->stats_vals[index >> 1] = data;
-+}
-+
-+static void catc_stats_timer(unsigned long data)
-+{
-+ struct catc *catc = (void *) data;
-+ int i;
-+
-+ for (i = 0; i < 8; i++)
-+ catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done);
-+
-+ mod_timer(&catc->timer, jiffies + STATS_UPDATE);
-+}
-+
-+/*
-+ * Receive modes. Broadcast, Multicast, Promisc.
-+ */
-+
-+static void catc_multicast(unsigned char *addr, u8 *multicast)
-+{
-+ u32 crc;
-+
-+ crc = ether_crc_le(6, addr);
-+ multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
-+}
-+
-+static void catc_set_multicast_list(struct net_device *netdev)
-+{
-+ struct catc *catc = netdev_priv(netdev);
-+ struct netdev_hw_addr *ha;
-+ u8 broadcast[ETH_ALEN];
-+ u8 rx = RxEnable | RxPolarity | RxMultiCast;
-+
-+ eth_broadcast_addr(broadcast);
-+ memset(catc->multicast, 0, 64);
-+
-+ catc_multicast(broadcast, catc->multicast);
-+ catc_multicast(netdev->dev_addr, catc->multicast);
-+
-+ if (netdev->flags & IFF_PROMISC) {
-+ memset(catc->multicast, 0xff, 64);
-+ rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc;
-+ }
-+
-+ if (netdev->flags & IFF_ALLMULTI) {
-+ memset(catc->multicast, 0xff, 64);
-+ } else {
-+ netdev_for_each_mc_addr(ha, netdev) {
-+ u32 crc = ether_crc_le(6, ha->addr);
-+ if (!catc->is_f5u011) {
-+ catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
-+ } else {
-+ catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7);
-+ }
-+ }
-+ }
-+ if (!catc->is_f5u011) {
-+ catc_set_reg_async(catc, RxUnit, rx);
-+ catc_write_mem_async(catc, 0xfa80, catc->multicast, 64);
-+ } else {
-+ f5u011_mchash_async(catc, catc->multicast);
-+ if (catc->rxmode[0] != rx) {
-+ catc->rxmode[0] = rx;
-+ netdev_dbg(catc->netdev,
-+ "Setting RX mode to %2.2X %2.2X\n",
-+ catc->rxmode[0], catc->rxmode[1]);
-+ f5u011_rxmode_async(catc, catc->rxmode);
-+ }
-+ }
-+}
-+
-+static void catc_get_drvinfo(struct net_device *dev,
-+ struct ethtool_drvinfo *info)
-+{
-+ struct catc *catc = netdev_priv(dev);
-+ strlcpy(info->driver, driver_name, sizeof(info->driver));
-+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
-+ usb_make_path(catc->usbdev, info->bus_info, sizeof(info->bus_info));
-+}
-+
-+static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-+{
-+ struct catc *catc = netdev_priv(dev);
-+ if (!catc->is_f5u011)
-+ return -EOPNOTSUPP;
-+
-+ cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
-+ cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
-+ ethtool_cmd_speed_set(cmd, SPEED_10);
-+ cmd->duplex = DUPLEX_HALF;
-+ cmd->port = PORT_TP;
-+ cmd->phy_address = 0;
-+ cmd->transceiver = XCVR_INTERNAL;
-+ cmd->autoneg = AUTONEG_DISABLE;
-+ cmd->maxtxpkt = 1;
-+ cmd->maxrxpkt = 1;
-+ return 0;
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_drvinfo = catc_get_drvinfo,
-+ .get_settings = catc_get_settings,
-+ .get_link = ethtool_op_get_link
-+};
-+
-+/*
-+ * Open, close.
-+ */
-+
-+static int catc_open(struct net_device *netdev)
-+{
-+ struct catc *catc = netdev_priv(netdev);
-+ int status;
-+
-+ catc->irq_urb->dev = catc->usbdev;
-+ if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
-+ dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n",
-+ status);
-+ return -1;
-+ }
-+
-+ netif_start_queue(netdev);
-+
-+ if (!catc->is_f5u011)
-+ mod_timer(&catc->timer, jiffies + STATS_UPDATE);
-+
-+ return 0;
-+}
-+
-+static int catc_stop(struct net_device *netdev)
-+{
-+ struct catc *catc = netdev_priv(netdev);
-+
-+ netif_stop_queue(netdev);
-+
-+ if (!catc->is_f5u011)
-+ del_timer_sync(&catc->timer);
-+
-+ usb_kill_urb(catc->rx_urb);
-+ usb_kill_urb(catc->tx_urb);
-+ usb_kill_urb(catc->irq_urb);
-+ usb_kill_urb(catc->ctrl_urb);
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops catc_netdev_ops = {
-+ .ndo_open = catc_open,
-+ .ndo_stop = catc_stop,
-+ .ndo_start_xmit = catc_start_xmit,
-+
-+ .ndo_tx_timeout = catc_tx_timeout,
-+ .ndo_set_rx_mode = catc_set_multicast_list,
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+};
-+
-+/*
-+ * USB probe, disconnect.
-+ */
-+
-+static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id)
-+{
-+ struct device *dev = &intf->dev;
-+ struct usb_device *usbdev = interface_to_usbdev(intf);
-+ struct net_device *netdev;
-+ struct catc *catc;
-+ u8 broadcast[ETH_ALEN];
-+ int i, pktsz;
-+
-+ if (usb_set_interface(usbdev,
-+ intf->altsetting->desc.bInterfaceNumber, 1)) {
-+ dev_err(dev, "Can't set altsetting 1.\n");
-+ return -EIO;
-+ }
-+
-+ netdev = alloc_etherdev(sizeof(struct catc));
-+ if (!netdev)
-+ return -ENOMEM;
-+
-+ catc = netdev_priv(netdev);
-+
-+ netdev->netdev_ops = &catc_netdev_ops;
-+ netdev->watchdog_timeo = TX_TIMEOUT;
-+ netdev->ethtool_ops = &ops;
-+
-+ catc->usbdev = usbdev;
-+ catc->netdev = netdev;
-+
-+ spin_lock_init(&catc->tx_lock);
-+ spin_lock_init(&catc->ctrl_lock);
-+
-+ init_timer(&catc->timer);
-+ catc->timer.data = (long) catc;
-+ catc->timer.function = catc_stats_timer;
-+
-+ catc->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ catc->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ catc->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if ((!catc->ctrl_urb) || (!catc->tx_urb) ||
-+ (!catc->rx_urb) || (!catc->irq_urb)) {
-+ dev_err(&intf->dev, "No free urbs available.\n");
-+ usb_free_urb(catc->ctrl_urb);
-+ usb_free_urb(catc->tx_urb);
-+ usb_free_urb(catc->rx_urb);
-+ usb_free_urb(catc->irq_urb);
-+ free_netdev(netdev);
-+ return -ENOMEM;
-+ }
-+
-+ /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */
-+ if (le16_to_cpu(usbdev->descriptor.idVendor) == 0x0423 &&
-+ le16_to_cpu(usbdev->descriptor.idProduct) == 0xa &&
-+ le16_to_cpu(catc->usbdev->descriptor.bcdDevice) == 0x0130) {
-+ dev_dbg(dev, "Testing for f5u011\n");
-+ catc->is_f5u011 = 1;
-+ atomic_set(&catc->recq_sz, 0);
-+ pktsz = RX_PKT_SZ;
-+ } else {
-+ pktsz = RX_MAX_BURST * (PKT_SZ + 2);
-+ }
-+
-+ usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
-+ NULL, NULL, 0, catc_ctrl_done, catc);
-+
-+ usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
-+ NULL, 0, catc_tx_done, catc);
-+
-+ usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
-+ catc->rx_buf, pktsz, catc_rx_done, catc);
-+
-+ usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
-+ catc->irq_buf, 2, catc_irq_done, catc, 1);
-+
-+ if (!catc->is_f5u011) {
-+ dev_dbg(dev, "Checking memory size\n");
-+
-+ i = 0x12345678;
-+ catc_write_mem(catc, 0x7a80, &i, 4);
-+ i = 0x87654321;
-+ catc_write_mem(catc, 0xfa80, &i, 4);
-+ catc_read_mem(catc, 0x7a80, &i, 4);
-+
-+ switch (i) {
-+ case 0x12345678:
-+ catc_set_reg(catc, TxBufCount, 8);
-+ catc_set_reg(catc, RxBufCount, 32);
-+ dev_dbg(dev, "64k Memory\n");
-+ break;
-+ default:
-+ dev_warn(&intf->dev,
-+ "Couldn't detect memory size, assuming 32k\n");
-+ case 0x87654321:
-+ catc_set_reg(catc, TxBufCount, 4);
-+ catc_set_reg(catc, RxBufCount, 16);
-+ dev_dbg(dev, "32k Memory\n");
-+ break;
-+ }
-+
-+ dev_dbg(dev, "Getting MAC from SEEROM.\n");
-+
-+ catc_get_mac(catc, netdev->dev_addr);
-+
-+ dev_dbg(dev, "Setting MAC into registers.\n");
-+
-+ for (i = 0; i < 6; i++)
-+ catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]);
-+
-+ dev_dbg(dev, "Filling the multicast list.\n");
-+
-+ eth_broadcast_addr(broadcast);
-+ catc_multicast(broadcast, catc->multicast);
-+ catc_multicast(netdev->dev_addr, catc->multicast);
-+ catc_write_mem(catc, 0xfa80, catc->multicast, 64);
-+
-+ dev_dbg(dev, "Clearing error counters.\n");
-+
-+ for (i = 0; i < 8; i++)
-+ catc_set_reg(catc, EthStats + i, 0);
-+ catc->last_stats = jiffies;
-+
-+ dev_dbg(dev, "Enabling.\n");
-+
-+ catc_set_reg(catc, MaxBurst, RX_MAX_BURST);
-+ catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits);
-+ catc_set_reg(catc, LEDCtrl, LEDLink);
-+ catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast);
-+ } else {
-+ dev_dbg(dev, "Performing reset\n");
-+ catc_reset(catc);
-+ catc_get_mac(catc, netdev->dev_addr);
-+
-+ dev_dbg(dev, "Setting RX Mode\n");
-+ catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast;
-+ catc->rxmode[1] = 0;
-+ f5u011_rxmode(catc, catc->rxmode);
-+ }
-+ dev_dbg(dev, "Init done.\n");
-+ printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, %pM.\n",
-+ netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate",
-+ usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr);
-+ usb_set_intfdata(intf, catc);
-+
-+ SET_NETDEV_DEV(netdev, &intf->dev);
-+ if (register_netdev(netdev) != 0) {
-+ usb_set_intfdata(intf, NULL);
-+ usb_free_urb(catc->ctrl_urb);
-+ usb_free_urb(catc->tx_urb);
-+ usb_free_urb(catc->rx_urb);
-+ usb_free_urb(catc->irq_urb);
-+ free_netdev(netdev);
-+ return -EIO;
-+ }
-+ return 0;
-+}
-+
-+static void catc_disconnect(struct usb_interface *intf)
-+{
-+ struct catc *catc = usb_get_intfdata(intf);
-+
-+ usb_set_intfdata(intf, NULL);
-+ if (catc) {
-+ unregister_netdev(catc->netdev);
-+ usb_free_urb(catc->ctrl_urb);
-+ usb_free_urb(catc->tx_urb);
-+ usb_free_urb(catc->rx_urb);
-+ usb_free_urb(catc->irq_urb);
-+ free_netdev(catc->netdev);
-+ }
-+}
-+
-+/*
-+ * Module functions and tables.
-+ */
-+
-+static struct usb_device_id catc_id_table [] = {
-+ { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */
-+ { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */
-+ { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */
-+ { }
-+};
-+
-+MODULE_DEVICE_TABLE(usb, catc_id_table);
-+
-+static struct usb_driver catc_driver = {
-+ .name = driver_name,
-+ .probe = catc_probe,
-+ .disconnect = catc_disconnect,
-+ .id_table = catc_id_table,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(catc_driver);
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/cdc_eem.c backports-4.2.6-1/drivers/net/usb/cdc_eem.c
---- backports-4.2.6-1.org/drivers/net/usb/cdc_eem.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/cdc_eem.c 2016-06-28 14:35:17.975307221 +0200
-@@ -0,0 +1,381 @@
-+/*
-+ * USB CDC EEM network interface driver
-+ * Copyright (C) 2009 Oberthur Technologies
-+ * by Omar Laazimani, Olivier Condemine
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ctype.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/gfp.h>
-+#include <linux/if_vlan.h>
-+
-+
-+/*
-+ * This driver is an implementation of the CDC "Ethernet Emulation
-+ * Model" (EEM) specification, which encapsulates Ethernet frames
-+ * for transport over USB using a simpler USB device model than the
-+ * previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet").
-+ *
-+ * For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf
-+ *
-+ * This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24,
-+ * 2.6.27 and 2.6.30rc2 kernel.
-+ * It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel).
-+ * build on 23-April-2009
-+ */
-+
-+#define EEM_HEAD 2 /* 2 byte header */
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static void eem_linkcmd_complete(struct urb *urb)
-+{
-+ dev_kfree_skb(urb->context);
-+ usb_free_urb(urb);
-+}
-+
-+static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct urb *urb;
-+ int status;
-+
-+ urb = usb_alloc_urb(0, GFP_ATOMIC);
-+ if (!urb)
-+ goto fail;
-+
-+ usb_fill_bulk_urb(urb, dev->udev, dev->out,
-+ skb->data, skb->len, eem_linkcmd_complete, skb);
-+
-+ status = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (status) {
-+ usb_free_urb(urb);
-+fail:
-+ dev_kfree_skb(skb);
-+ netdev_warn(dev->net, "link cmd failure\n");
-+ return;
-+ }
-+}
-+
-+static int eem_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int status = 0;
-+
-+ status = usbnet_get_endpoints(dev, intf);
-+ if (status < 0) {
-+ usb_set_intfdata(intf, NULL);
-+ usb_driver_release_interface(driver_of(intf), intf);
-+ return status;
-+ }
-+
-+ /* no jumbogram (16K) support for now */
-+
-+ dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN;
-+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-+
-+ return 0;
-+}
-+
-+/*
-+ * EEM permits packing multiple Ethernet frames into USB transfers
-+ * (a "bundle"), but for TX we don't try to do that.
-+ */
-+static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ struct sk_buff *skb2 = NULL;
-+ u16 len = skb->len;
-+ u32 crc = 0;
-+ int padlen = 0;
-+
-+ /* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is
-+ * zero, stick two bytes of zero length EEM packet on the end.
-+ * Else the framework would add invalid single byte padding,
-+ * since it can't know whether ZLPs will be handled right by
-+ * all the relevant hardware and software.
-+ */
-+ if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket))
-+ padlen += 2;
-+
-+ if (!skb_cloned(skb)) {
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+
-+ if ((tailroom >= ETH_FCS_LEN + padlen) &&
-+ (headroom >= EEM_HEAD))
-+ goto done;
-+
-+ if ((headroom + tailroom)
-+ > (EEM_HEAD + ETH_FCS_LEN + padlen)) {
-+ skb->data = memmove(skb->head +
-+ EEM_HEAD,
-+ skb->data,
-+ skb->len);
-+ skb_set_tail_pointer(skb, len);
-+ goto done;
-+ }
-+ }
-+
-+ skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags);
-+ if (!skb2)
-+ return NULL;
-+
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+
-+done:
-+ /* we don't use the "no Ethernet CRC" option */
-+ crc = crc32_le(~0, skb->data, skb->len);
-+ crc = ~crc;
-+
-+ put_unaligned_le32(crc, skb_put(skb, 4));
-+
-+ /* EEM packet header format:
-+ * b0..13: length of ethernet frame
-+ * b14: bmCRC (1 == valid Ethernet CRC)
-+ * b15: bmType (0 == data)
-+ */
-+ len = skb->len;
-+ put_unaligned_le16(BIT(14) | len, skb_push(skb, 2));
-+
-+ /* Bundle a zero length EEM packet if needed */
-+ if (padlen)
-+ put_unaligned_le16(0, skb_put(skb, 2));
-+
-+ return skb;
-+}
-+
-+static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ /*
-+ * Our task here is to strip off framing, leaving skb with one
-+ * data frame for the usbnet framework code to process. But we
-+ * may have received multiple EEM payloads, or command payloads.
-+ * So we must process _everything_ as if it's a header, except
-+ * maybe the last data payload
-+ *
-+ * REVISIT the framework needs updating so that when we consume
-+ * all payloads (the last or only message was a command, or a
-+ * zero length EEM packet) that is not accounted as an rx_error.
-+ */
-+ do {
-+ struct sk_buff *skb2 = NULL;
-+ u16 header;
-+ u16 len = 0;
-+
-+ /* incomplete EEM header? */
-+ if (skb->len < EEM_HEAD)
-+ return 0;
-+
-+ /*
-+ * EEM packet header format:
-+ * b0..14: EEM type dependent (Data or Command)
-+ * b15: bmType
-+ */
-+ header = get_unaligned_le16(skb->data);
-+ skb_pull(skb, EEM_HEAD);
-+
-+ /*
-+ * The bmType bit helps to denote when EEM
-+ * packet is data or command :
-+ * bmType = 0 : EEM data payload
-+ * bmType = 1 : EEM (link) command
-+ */
-+ if (header & BIT(15)) {
-+ u16 bmEEMCmd;
-+
-+ /*
-+ * EEM (link) command packet:
-+ * b0..10: bmEEMCmdParam
-+ * b11..13: bmEEMCmd
-+ * b14: bmReserved (must be 0)
-+ * b15: 1 (EEM command)
-+ */
-+ if (header & BIT(14)) {
-+ netdev_dbg(dev->net, "reserved command %04x\n",
-+ header);
-+ continue;
-+ }
-+
-+ bmEEMCmd = (header >> 11) & 0x7;
-+ switch (bmEEMCmd) {
-+
-+ /* Responding to echo requests is mandatory. */
-+ case 0: /* Echo command */
-+ len = header & 0x7FF;
-+
-+ /* bogus command? */
-+ if (skb->len < len)
-+ return 0;
-+
-+ skb2 = skb_clone(skb, GFP_ATOMIC);
-+ if (unlikely(!skb2))
-+ goto next;
-+ skb_trim(skb2, len);
-+ put_unaligned_le16(BIT(15) | (1 << 11) | len,
-+ skb_push(skb2, 2));
-+ eem_linkcmd(dev, skb2);
-+ break;
-+
-+ /*
-+ * Host may choose to ignore hints.
-+ * - suspend: peripheral ready to suspend
-+ * - response: suggest N millisec polling
-+ * - response complete: suggest N sec polling
-+ *
-+ * Suspend is reported and maybe heeded.
-+ */
-+ case 2: /* Suspend hint */
-+ usbnet_device_suggests_idle(dev);
-+ continue;
-+ case 3: /* Response hint */
-+ case 4: /* Response complete hint */
-+ continue;
-+
-+ /*
-+ * Hosts should never receive host-to-peripheral
-+ * or reserved command codes; or responses to an
-+ * echo command we didn't send.
-+ */
-+ case 1: /* Echo response */
-+ case 5: /* Tickle */
-+ default: /* reserved */
-+ netdev_warn(dev->net,
-+ "unexpected link command %d\n",
-+ bmEEMCmd);
-+ continue;
-+ }
-+
-+ } else {
-+ u32 crc, crc2;
-+ int is_last;
-+
-+ /* zero length EEM packet? */
-+ if (header == 0)
-+ continue;
-+
-+ /*
-+ * EEM data packet header :
-+ * b0..13: length of ethernet frame
-+ * b14: bmCRC
-+ * b15: 0 (EEM data)
-+ */
-+ len = header & 0x3FFF;
-+
-+ /* bogus EEM payload? */
-+ if (skb->len < len)
-+ return 0;
-+
-+ /* bogus ethernet frame? */
-+ if (len < (ETH_HLEN + ETH_FCS_LEN))
-+ goto next;
-+
-+ /*
-+ * Treat the last payload differently: framework
-+ * code expects our "fixup" to have stripped off
-+ * headers, so "skb" is a data packet (or error).
-+ * Else if it's not the last payload, keep "skb"
-+ * for further processing.
-+ */
-+ is_last = (len == skb->len);
-+ if (is_last)
-+ skb2 = skb;
-+ else {
-+ skb2 = skb_clone(skb, GFP_ATOMIC);
-+ if (unlikely(!skb2))
-+ return 0;
-+ }
-+
-+ /*
-+ * The bmCRC helps to denote when the CRC field in
-+ * the Ethernet frame contains a calculated CRC:
-+ * bmCRC = 1 : CRC is calculated
-+ * bmCRC = 0 : CRC = 0xDEADBEEF
-+ */
-+ if (header & BIT(14)) {
-+ crc = get_unaligned_le32(skb2->data
-+ + len - ETH_FCS_LEN);
-+ crc2 = ~crc32_le(~0, skb2->data, skb2->len
-+ - ETH_FCS_LEN);
-+ } else {
-+ crc = get_unaligned_be32(skb2->data
-+ + len - ETH_FCS_LEN);
-+ crc2 = 0xdeadbeef;
-+ }
-+ skb_trim(skb2, len - ETH_FCS_LEN);
-+
-+ if (is_last)
-+ return crc == crc2;
-+
-+ if (unlikely(crc != crc2)) {
-+ dev->net->stats.rx_errors++;
-+ dev_kfree_skb_any(skb2);
-+ } else
-+ usbnet_skb_return(dev, skb2);
-+ }
-+
-+next:
-+ skb_pull(skb, len);
-+ } while (skb->len);
-+
-+ return 1;
-+}
-+
-+static const struct driver_info eem_info = {
-+ .description = "CDC EEM Device",
-+ .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
-+ .bind = eem_bind,
-+ .rx_fixup = eem_rx_fixup,
-+ .tx_fixup = eem_tx_fixup,
-+};
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static const struct usb_device_id products[] = {
-+{
-+ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM,
-+ USB_CDC_PROTO_EEM),
-+ .driver_info = (unsigned long) &eem_info,
-+},
-+{
-+ /* EMPTY == end of list */
-+},
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver eem_driver = {
-+ .name = "cdc_eem",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(eem_driver);
-+
-+MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>");
-+MODULE_DESCRIPTION("USB CDC EEM");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/cdc-phonet.c backports-4.2.6-1/drivers/net/usb/cdc-phonet.c
---- backports-4.2.6-1.org/drivers/net/usb/cdc-phonet.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/cdc-phonet.c 2016-06-28 14:35:17.975307221 +0200
-@@ -0,0 +1,466 @@
-+/*
-+ * phonet.c -- USB CDC Phonet host driver
-+ *
-+ * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved.
-+ *
-+ * Author: Rémi Denis-Courmont
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Â See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-+ * 02110-1301 USA
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/gfp.h>
-+#include <linux/usb.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/netdevice.h>
-+#include <linux/if_arp.h>
-+#include <linux/if_phonet.h>
-+#include <linux/phonet.h>
-+
-+#define PN_MEDIA_USB 0x1B
-+
-+static const unsigned rxq_size = 17;
-+
-+struct usbpn_dev {
-+ struct net_device *dev;
-+
-+ struct usb_interface *intf, *data_intf;
-+ struct usb_device *usb;
-+ unsigned int tx_pipe, rx_pipe;
-+ u8 active_setting;
-+ u8 disconnected;
-+
-+ unsigned tx_queue;
-+ spinlock_t tx_lock;
-+
-+ spinlock_t rx_lock;
-+ struct sk_buff *rx_skb;
-+ struct urb *urbs[0];
-+};
-+
-+static void tx_complete(struct urb *req);
-+static void rx_complete(struct urb *req);
-+
-+/*
-+ * Network device callbacks
-+ */
-+static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct usbpn_dev *pnd = netdev_priv(dev);
-+ struct urb *req = NULL;
-+ unsigned long flags;
-+ int err;
-+
-+ if (skb->protocol != htons(ETH_P_PHONET))
-+ goto drop;
-+
-+ req = usb_alloc_urb(0, GFP_ATOMIC);
-+ if (!req)
-+ goto drop;
-+ usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len,
-+ tx_complete, skb);
-+ req->transfer_flags = URB_ZERO_PACKET;
-+ err = usb_submit_urb(req, GFP_ATOMIC);
-+ if (err) {
-+ usb_free_urb(req);
-+ goto drop;
-+ }
-+
-+ spin_lock_irqsave(&pnd->tx_lock, flags);
-+ pnd->tx_queue++;
-+ if (pnd->tx_queue >= dev->tx_queue_len)
-+ netif_stop_queue(dev);
-+ spin_unlock_irqrestore(&pnd->tx_lock, flags);
-+ return NETDEV_TX_OK;
-+
-+drop:
-+ dev_kfree_skb(skb);
-+ dev->stats.tx_dropped++;
-+ return NETDEV_TX_OK;
-+}
-+
-+static void tx_complete(struct urb *req)
-+{
-+ struct sk_buff *skb = req->context;
-+ struct net_device *dev = skb->dev;
-+ struct usbpn_dev *pnd = netdev_priv(dev);
-+ int status = req->status;
-+
-+ switch (status) {
-+ case 0:
-+ dev->stats.tx_bytes += skb->len;
-+ break;
-+
-+ case -ENOENT:
-+ case -ECONNRESET:
-+ case -ESHUTDOWN:
-+ dev->stats.tx_aborted_errors++;
-+ default:
-+ dev->stats.tx_errors++;
-+ dev_dbg(&dev->dev, "TX error (%d)\n", status);
-+ }
-+ dev->stats.tx_packets++;
-+
-+ spin_lock(&pnd->tx_lock);
-+ pnd->tx_queue--;
-+ netif_wake_queue(dev);
-+ spin_unlock(&pnd->tx_lock);
-+
-+ dev_kfree_skb_any(skb);
-+ usb_free_urb(req);
-+}
-+
-+static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags)
-+{
-+ struct net_device *dev = pnd->dev;
-+ struct page *page;
-+ int err;
-+
-+ page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
-+ if (!page)
-+ return -ENOMEM;
-+
-+ usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page),
-+ PAGE_SIZE, rx_complete, dev);
-+ req->transfer_flags = 0;
-+ err = usb_submit_urb(req, gfp_flags);
-+ if (unlikely(err)) {
-+ dev_dbg(&dev->dev, "RX submit error (%d)\n", err);
-+ put_page(page);
-+ }
-+ return err;
-+}
-+
-+static void rx_complete(struct urb *req)
-+{
-+ struct net_device *dev = req->context;
-+ struct usbpn_dev *pnd = netdev_priv(dev);
-+ struct page *page = virt_to_page(req->transfer_buffer);
-+ struct sk_buff *skb;
-+ unsigned long flags;
-+ int status = req->status;
-+
-+ switch (status) {
-+ case 0:
-+ spin_lock_irqsave(&pnd->rx_lock, flags);
-+ skb = pnd->rx_skb;
-+ if (!skb) {
-+ skb = pnd->rx_skb = netdev_alloc_skb(dev, 12);
-+ if (likely(skb)) {
-+ /* Can't use pskb_pull() on page in IRQ */
-+ memcpy(skb_put(skb, 1), page_address(page), 1);
-+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-+ page, 1, req->actual_length,
-+ PAGE_SIZE);
-+ page = NULL;
-+ }
-+ } else {
-+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
-+ page, 0, req->actual_length,
-+ PAGE_SIZE);
-+ page = NULL;
-+ }
-+ if (req->actual_length < PAGE_SIZE)
-+ pnd->rx_skb = NULL; /* Last fragment */
-+ else
-+ skb = NULL;
-+ spin_unlock_irqrestore(&pnd->rx_lock, flags);
-+ if (skb) {
-+ skb->protocol = htons(ETH_P_PHONET);
-+ skb_reset_mac_header(skb);
-+ __skb_pull(skb, 1);
-+ skb->dev = dev;
-+ dev->stats.rx_packets++;
-+ dev->stats.rx_bytes += skb->len;
-+
-+ netif_rx(skb);
-+ }
-+ goto resubmit;
-+
-+ case -ENOENT:
-+ case -ECONNRESET:
-+ case -ESHUTDOWN:
-+ req = NULL;
-+ break;
-+
-+ case -EOVERFLOW:
-+ dev->stats.rx_over_errors++;
-+ dev_dbg(&dev->dev, "RX overflow\n");
-+ break;
-+
-+ case -EILSEQ:
-+ dev->stats.rx_crc_errors++;
-+ break;
-+ }
-+
-+ dev->stats.rx_errors++;
-+resubmit:
-+ if (page)
-+ put_page(page);
-+ if (req)
-+ rx_submit(pnd, req, GFP_ATOMIC);
-+}
-+
-+static int usbpn_close(struct net_device *dev);
-+
-+static int usbpn_open(struct net_device *dev)
-+{
-+ struct usbpn_dev *pnd = netdev_priv(dev);
-+ int err;
-+ unsigned i;
-+ unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
-+
-+ err = usb_set_interface(pnd->usb, num, pnd->active_setting);
-+ if (err)
-+ return err;
-+
-+ for (i = 0; i < rxq_size; i++) {
-+ struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
-+
-+ if (!req || rx_submit(pnd, req, GFP_KERNEL)) {
-+ usb_free_urb(req);
-+ usbpn_close(dev);
-+ return -ENOMEM;
-+ }
-+ pnd->urbs[i] = req;
-+ }
-+
-+ netif_wake_queue(dev);
-+ return 0;
-+}
-+
-+static int usbpn_close(struct net_device *dev)
-+{
-+ struct usbpn_dev *pnd = netdev_priv(dev);
-+ unsigned i;
-+ unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber;
-+
-+ netif_stop_queue(dev);
-+
-+ for (i = 0; i < rxq_size; i++) {
-+ struct urb *req = pnd->urbs[i];
-+
-+ if (!req)
-+ continue;
-+ usb_kill_urb(req);
-+ usb_free_urb(req);
-+ pnd->urbs[i] = NULL;
-+ }
-+
-+ return usb_set_interface(pnd->usb, num, !pnd->active_setting);
-+}
-+
-+static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-+{
-+ struct if_phonet_req *req = (struct if_phonet_req *)ifr;
-+
-+ switch (cmd) {
-+ case SIOCPNGAUTOCONF:
-+ req->ifr_phonet_autoconf.device = PN_DEV_PC;
-+ return 0;
-+ }
-+ return -ENOIOCTLCMD;
-+}
-+
-+static int usbpn_set_mtu(struct net_device *dev, int new_mtu)
-+{
-+ if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU))
-+ return -EINVAL;
-+
-+ dev->mtu = new_mtu;
-+ return 0;
-+}
-+
-+static const struct net_device_ops usbpn_ops = {
-+ .ndo_open = usbpn_open,
-+ .ndo_stop = usbpn_close,
-+ .ndo_start_xmit = usbpn_xmit,
-+ .ndo_do_ioctl = usbpn_ioctl,
-+ .ndo_change_mtu = usbpn_set_mtu,
-+};
-+
-+static void usbpn_setup(struct net_device *dev)
-+{
-+ dev->features = 0;
-+ dev->netdev_ops = &usbpn_ops,
-+ dev->header_ops = &phonet_header_ops;
-+ dev->type = ARPHRD_PHONET;
-+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-+ dev->mtu = PHONET_MAX_MTU;
-+ dev->hard_header_len = 1;
-+ dev->dev_addr[0] = PN_MEDIA_USB;
-+ dev->addr_len = 1;
-+ dev->tx_queue_len = 3;
-+
-+ dev->destructor = free_netdev;
-+}
-+
-+/*
-+ * USB driver callbacks
-+ */
-+static struct usb_device_id usbpn_ids[] = {
-+ {
-+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
-+ | USB_DEVICE_ID_MATCH_INT_CLASS
-+ | USB_DEVICE_ID_MATCH_INT_SUBCLASS,
-+ .idVendor = 0x0421, /* Nokia */
-+ .bInterfaceClass = USB_CLASS_COMM,
-+ .bInterfaceSubClass = 0xFE,
-+ },
-+ { },
-+};
-+
-+MODULE_DEVICE_TABLE(usb, usbpn_ids);
-+
-+static struct usb_driver usbpn_driver;
-+
-+static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
-+{
-+ static const char ifname[] = "usbpn%d";
-+ const struct usb_cdc_union_desc *union_header = NULL;
-+ const struct usb_host_interface *data_desc;
-+ struct usb_interface *data_intf;
-+ struct usb_device *usbdev = interface_to_usbdev(intf);
-+ struct net_device *dev;
-+ struct usbpn_dev *pnd;
-+ u8 *data;
-+ int phonet = 0;
-+ int len, err;
-+
-+ data = intf->altsetting->extra;
-+ len = intf->altsetting->extralen;
-+ while (len >= 3) {
-+ u8 dlen = data[0];
-+ if (dlen < 3)
-+ return -EINVAL;
-+
-+ /* bDescriptorType */
-+ if (data[1] == USB_DT_CS_INTERFACE) {
-+ /* bDescriptorSubType */
-+ switch (data[2]) {
-+ case USB_CDC_UNION_TYPE:
-+ if (union_header || dlen < 5)
-+ break;
-+ union_header =
-+ (struct usb_cdc_union_desc *)data;
-+ break;
-+ case 0xAB:
-+ phonet = 1;
-+ break;
-+ }
-+ }
-+ data += dlen;
-+ len -= dlen;
-+ }
-+
-+ if (!union_header || !phonet)
-+ return -EINVAL;
-+
-+ data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
-+ if (data_intf == NULL)
-+ return -ENODEV;
-+ /* Data interface has one inactive and one active setting */
-+ if (data_intf->num_altsetting != 2)
-+ return -EINVAL;
-+ if (data_intf->altsetting[0].desc.bNumEndpoints == 0 &&
-+ data_intf->altsetting[1].desc.bNumEndpoints == 2)
-+ data_desc = data_intf->altsetting + 1;
-+ else
-+ if (data_intf->altsetting[0].desc.bNumEndpoints == 2 &&
-+ data_intf->altsetting[1].desc.bNumEndpoints == 0)
-+ data_desc = data_intf->altsetting;
-+ else
-+ return -EINVAL;
-+
-+ dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
-+ ifname, NET_NAME_UNKNOWN, usbpn_setup);
-+ if (!dev)
-+ return -ENOMEM;
-+
-+ pnd = netdev_priv(dev);
-+ SET_NETDEV_DEV(dev, &intf->dev);
-+
-+ pnd->dev = dev;
-+ pnd->usb = usbdev;
-+ pnd->intf = intf;
-+ pnd->data_intf = data_intf;
-+ spin_lock_init(&pnd->tx_lock);
-+ spin_lock_init(&pnd->rx_lock);
-+ /* Endpoints */
-+ if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
-+ pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
-+ data_desc->endpoint[0].desc.bEndpointAddress);
-+ pnd->tx_pipe = usb_sndbulkpipe(usbdev,
-+ data_desc->endpoint[1].desc.bEndpointAddress);
-+ } else {
-+ pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
-+ data_desc->endpoint[1].desc.bEndpointAddress);
-+ pnd->tx_pipe = usb_sndbulkpipe(usbdev,
-+ data_desc->endpoint[0].desc.bEndpointAddress);
-+ }
-+ pnd->active_setting = data_desc - data_intf->altsetting;
-+
-+ err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
-+ if (err)
-+ goto out;
-+
-+ /* Force inactive mode until the network device is brought UP */
-+ usb_set_interface(usbdev, union_header->bSlaveInterface0,
-+ !pnd->active_setting);
-+ usb_set_intfdata(intf, pnd);
-+
-+ err = register_netdev(dev);
-+ if (err) {
-+ usb_driver_release_interface(&usbpn_driver, data_intf);
-+ goto out;
-+ }
-+
-+ dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
-+ return 0;
-+
-+out:
-+ usb_set_intfdata(intf, NULL);
-+ free_netdev(dev);
-+ return err;
-+}
-+
-+static void usbpn_disconnect(struct usb_interface *intf)
-+{
-+ struct usbpn_dev *pnd = usb_get_intfdata(intf);
-+
-+ if (pnd->disconnected)
-+ return;
-+
-+ pnd->disconnected = 1;
-+ usb_driver_release_interface(&usbpn_driver,
-+ (pnd->intf == intf) ? pnd->data_intf : pnd->intf);
-+ unregister_netdev(pnd->dev);
-+}
-+
-+static struct usb_driver usbpn_driver = {
-+ .name = "cdc_phonet",
-+ .probe = usbpn_probe,
-+ .disconnect = usbpn_disconnect,
-+ .id_table = usbpn_ids,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(usbpn_driver);
-+
-+MODULE_AUTHOR("Remi Denis-Courmont");
-+MODULE_DESCRIPTION("USB CDC Phonet host interface");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/cdc_subset.c backports-4.2.6-1/drivers/net/usb/cdc_subset.c
---- backports-4.2.6-1.org/drivers/net/usb/cdc_subset.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/cdc_subset.c 2016-06-28 14:35:17.975307221 +0200
-@@ -0,0 +1,369 @@
-+/*
-+ * Simple "CDC Subset" USB Networking Links
-+ * Copyright (C) 2000-2005 by David Brownell
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kmod.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+
-+
-+/*
-+ * This supports simple USB network links that don't require any special
-+ * framing or hardware control operations. The protocol used here is a
-+ * strict subset of CDC Ethernet, with three basic differences reflecting
-+ * the goal that almost any hardware should run it:
-+ *
-+ * - Minimal runtime control: one interface, no altsettings, and
-+ * no vendor or class specific control requests. If a device is
-+ * configured, it is allowed to exchange packets with the host.
-+ * Fancier models would mean not working on some hardware.
-+ *
-+ * - Minimal manufacturing control: no IEEE "Organizationally
-+ * Unique ID" required, or an EEPROMs to store one. Each host uses
-+ * one random "locally assigned" Ethernet address instead, which can
-+ * of course be overridden using standard tools like "ifconfig".
-+ * (With 2^46 such addresses, same-net collisions are quite rare.)
-+ *
-+ * - There is no additional framing data for USB. Packets are written
-+ * exactly as in CDC Ethernet, starting with an Ethernet header and
-+ * terminated by a short packet. However, the host will never send a
-+ * zero length packet; some systems can't handle those robustly.
-+ *
-+ * Anything that can transmit and receive USB bulk packets can implement
-+ * this protocol. That includes both smart peripherals and quite a lot
-+ * of "host-to-host" USB cables (which embed two devices back-to-back).
-+ *
-+ * Note that although Linux may use many of those host-to-host links
-+ * with this "cdc_subset" framing, that doesn't mean there may not be a
-+ * better approach. Handling the "other end unplugs/replugs" scenario
-+ * well tends to require chip-specific vendor requests. Also, Windows
-+ * peers at the other end of host-to-host cables may expect their own
-+ * framing to be used rather than this "cdc_subset" model.
-+ */
-+
-+#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX)
-+/* PDA style devices are always connected if present */
-+static int always_connected (struct usbnet *dev)
-+{
-+ return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_USB_ALI_M5632
-+#define HAVE_HARDWARE
-+
-+/*-------------------------------------------------------------------------
-+ *
-+ * ALi M5632 driver ... does high speed
-+ *
-+ * NOTE that the MS-Windows drivers for this chip use some funky and
-+ * (naturally) undocumented 7-byte prefix to each packet, so this is a
-+ * case where we don't currently interoperate. Also, once you unplug
-+ * one end of the cable, you need to replug the other end too ... since
-+ * chip docs are unavailable, there's no way to reset the relevant state
-+ * short of a power cycle.
-+ *
-+ *-------------------------------------------------------------------------*/
-+
-+static void m5632_recover(struct usbnet *dev)
-+{
-+ struct usb_device *udev = dev->udev;
-+ struct usb_interface *intf = dev->intf;
-+ int r;
-+
-+ r = usb_lock_device_for_reset(udev, intf);
-+ if (r < 0)
-+ return;
-+
-+ usb_reset_device(udev);
-+ usb_unlock_device(udev);
-+}
-+
-+static const struct driver_info ali_m5632_info = {
-+ .description = "ALi M5632",
-+ .flags = FLAG_POINTTOPOINT,
-+ .recover = m5632_recover,
-+};
-+
-+#endif
-+
-+#ifdef CONFIG_USB_AN2720
-+#define HAVE_HARDWARE
-+
-+/*-------------------------------------------------------------------------
-+ *
-+ * AnchorChips 2720 driver ... http://www.cypress.com
-+ *
-+ * This doesn't seem to have a way to detect whether the peer is
-+ * connected, or need any reset handshaking. It's got pretty big
-+ * internal buffers (handles most of a frame's worth of data).
-+ * Chip data sheets don't describe any vendor control messages.
-+ *
-+ *-------------------------------------------------------------------------*/
-+
-+static const struct driver_info an2720_info = {
-+ .description = "AnchorChips/Cypress 2720",
-+ .flags = FLAG_POINTTOPOINT,
-+ // no reset available!
-+ // no check_connect available!
-+
-+ .in = 2, .out = 2, // direction distinguishes these
-+};
-+
-+#endif /* CONFIG_USB_AN2720 */
-+
-+\f
-+#ifdef CONFIG_USB_BELKIN
-+#define HAVE_HARDWARE
-+
-+/*-------------------------------------------------------------------------
-+ *
-+ * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller
-+ *
-+ * ... also two eTEK designs, including one sold as "Advance USBNET"
-+ *
-+ *-------------------------------------------------------------------------*/
-+
-+static const struct driver_info belkin_info = {
-+ .description = "Belkin, eTEK, or compatible",
-+ .flags = FLAG_POINTTOPOINT,
-+};
-+
-+#endif /* CONFIG_USB_BELKIN */
-+
-+
-+\f
-+#ifdef CONFIG_USB_EPSON2888
-+#define HAVE_HARDWARE
-+
-+/*-------------------------------------------------------------------------
-+ *
-+ * EPSON USB clients
-+ *
-+ * This is the same idea as Linux PDAs (below) except the firmware in the
-+ * device might not be Tux-powered. Epson provides reference firmware that
-+ * implements this interface. Product developers can reuse or modify that
-+ * code, such as by using their own product and vendor codes.
-+ *
-+ * Support was from Juro Bystricky <bystricky.juro@erd.epson.com>
-+ *
-+ *-------------------------------------------------------------------------*/
-+
-+static const struct driver_info epson2888_info = {
-+ .description = "Epson USB Device",
-+ .check_connect = always_connected,
-+ .flags = FLAG_POINTTOPOINT,
-+
-+ .in = 4, .out = 3,
-+};
-+
-+#endif /* CONFIG_USB_EPSON2888 */
-+
-+\f
-+/*-------------------------------------------------------------------------
-+ *
-+ * info from Jonathan McDowell <noodles@earth.li>
-+ *
-+ *-------------------------------------------------------------------------*/
-+#ifdef CONFIG_USB_KC2190
-+#define HAVE_HARDWARE
-+static const struct driver_info kc2190_info = {
-+ .description = "KC Technology KC-190",
-+ .flags = FLAG_POINTTOPOINT,
-+};
-+#endif /* CONFIG_USB_KC2190 */
-+
-+\f
-+#ifdef CONFIG_USB_ARMLINUX
-+#define HAVE_HARDWARE
-+
-+/*-------------------------------------------------------------------------
-+ *
-+ * Intel's SA-1100 chip integrates basic USB support, and is used
-+ * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more.
-+ * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
-+ * network using minimal USB framing data.
-+ *
-+ * This describes the driver currently in standard ARM Linux kernels.
-+ * The Zaurus uses a different driver (see later).
-+ *
-+ * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support
-+ * and different USB endpoint numbering than the SA1100 devices. The
-+ * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100
-+ * so we rely on the endpoint descriptors.
-+ *
-+ *-------------------------------------------------------------------------*/
-+
-+static const struct driver_info linuxdev_info = {
-+ .description = "Linux Device",
-+ .check_connect = always_connected,
-+ .flags = FLAG_POINTTOPOINT,
-+};
-+
-+static const struct driver_info yopy_info = {
-+ .description = "Yopy",
-+ .check_connect = always_connected,
-+ .flags = FLAG_POINTTOPOINT,
-+};
-+
-+static const struct driver_info blob_info = {
-+ .description = "Boot Loader OBject",
-+ .check_connect = always_connected,
-+ .flags = FLAG_POINTTOPOINT,
-+};
-+
-+#endif /* CONFIG_USB_ARMLINUX */
-+
-+\f
-+/*-------------------------------------------------------------------------*/
-+
-+#ifndef HAVE_HARDWARE
-+#warning You need to configure some hardware for this driver
-+#endif
-+
-+/*
-+ * chip vendor names won't normally be on the cables, and
-+ * may not be on the device.
-+ */
-+
-+static const struct usb_device_id products [] = {
-+
-+#ifdef CONFIG_USB_ALI_M5632
-+{
-+ USB_DEVICE (0x0402, 0x5632), // ALi defaults
-+ .driver_info = (unsigned long) &ali_m5632_info,
-+},
-+{
-+ USB_DEVICE (0x182d,0x207c), // SiteCom CN-124
-+ .driver_info = (unsigned long) &ali_m5632_info,
-+},
-+#endif
-+
-+#ifdef CONFIG_USB_AN2720
-+{
-+ USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults
-+ .driver_info = (unsigned long) &an2720_info,
-+}, {
-+ USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET
-+ .driver_info = (unsigned long) &an2720_info,
-+},
-+#endif
-+
-+#ifdef CONFIG_USB_BELKIN
-+{
-+ USB_DEVICE (0x050d, 0x0004), // Belkin
-+ .driver_info = (unsigned long) &belkin_info,
-+}, {
-+ USB_DEVICE (0x056c, 0x8100), // eTEK
-+ .driver_info = (unsigned long) &belkin_info,
-+}, {
-+ USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK)
-+ .driver_info = (unsigned long) &belkin_info,
-+},
-+#endif
-+
-+#ifdef CONFIG_USB_EPSON2888
-+{
-+ USB_DEVICE (0x0525, 0x2888), // EPSON USB client
-+ .driver_info = (unsigned long) &epson2888_info,
-+},
-+#endif
-+
-+#ifdef CONFIG_USB_KC2190
-+{
-+ USB_DEVICE (0x050f, 0x0190), // KC-190
-+ .driver_info = (unsigned long) &kc2190_info,
-+},
-+#endif
-+
-+#ifdef CONFIG_USB_ARMLINUX
-+/*
-+ * SA-1100 using standard ARM Linux kernels, or compatible.
-+ * Often used when talking to Linux PDAs (iPaq, Yopy, etc).
-+ * The sa-1100 "usb-eth" driver handles the basic framing.
-+ *
-+ * PXA25x or PXA210 ... these use a "usb-eth" driver much like
-+ * the sa1100 one, but hardware uses different endpoint numbers.
-+ *
-+ * Or the Linux "Ethernet" gadget on hardware that can't talk
-+ * CDC Ethernet (e.g., no altsettings), in either of two modes:
-+ * - acting just like the old "usb-eth" firmware, though
-+ * the implementation is different
-+ * - supporting RNDIS as the first/default configuration for
-+ * MS-Windows interop; Linux needs to use the other config
-+ */
-+{
-+ // 1183 = 0x049F, both used as hex values?
-+ // Compaq "Itsy" vendor/product id
-+ USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible
-+ .driver_info = (unsigned long) &linuxdev_info,
-+}, {
-+ USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy"
-+ .driver_info = (unsigned long) &yopy_info,
-+}, {
-+ USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader
-+ .driver_info = (unsigned long) &blob_info,
-+}, {
-+ USB_DEVICE (0x1286, 0x8001), // "blob" bootloader
-+ .driver_info = (unsigned long) &blob_info,
-+}, {
-+ // Linux Ethernet/RNDIS gadget, mostly on PXA, second config
-+ // e.g. Gumstix, current OpenZaurus, ... or anything else
-+ // that just enables this gadget option.
-+ USB_DEVICE (0x0525, 0xa4a2),
-+ .driver_info = (unsigned long) &linuxdev_info,
-+},
-+#endif
-+
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+/*-------------------------------------------------------------------------*/
-+static int dummy_prereset(struct usb_interface *intf)
-+{
-+ return 0;
-+}
-+
-+static int dummy_postreset(struct usb_interface *intf)
-+{
-+ return 0;
-+}
-+
-+static struct usb_driver cdc_subset_driver = {
-+ .name = "cdc_subset",
-+ .probe = usbnet_probe,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .pre_reset = dummy_prereset,
-+ .post_reset = dummy_postreset,
-+ .disconnect = usbnet_disconnect,
-+ .id_table = products,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(cdc_subset_driver);
-+
-+MODULE_AUTHOR("David Brownell");
-+MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/cx82310_eth.c backports-4.2.6-1/drivers/net/usb/cx82310_eth.c
---- backports-4.2.6-1.org/drivers/net/usb/cx82310_eth.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/cx82310_eth.c 2016-06-28 14:35:17.978640554 +0200
-@@ -0,0 +1,353 @@
-+/*
-+ * Driver for USB ethernet port of Conexant CX82310-based ADSL routers
-+ * Copyright (C) 2010 by Ondrej Zary
-+ * some parts inspired by the cxacru driver
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+
-+enum cx82310_cmd {
-+ CMD_START = 0x84, /* no effect? */
-+ CMD_STOP = 0x85, /* no effect? */
-+ CMD_GET_STATUS = 0x90, /* returns nothing? */
-+ CMD_GET_MAC_ADDR = 0x91, /* read MAC address */
-+ CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */
-+ CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */
-+};
-+
-+enum cx82310_status {
-+ STATUS_UNDEFINED,
-+ STATUS_SUCCESS,
-+ STATUS_ERROR,
-+ STATUS_UNSUPPORTED,
-+ STATUS_UNIMPLEMENTED,
-+ STATUS_PARAMETER_ERROR,
-+ STATUS_DBG_LOOPBACK,
-+};
-+
-+#define CMD_PACKET_SIZE 64
-+#define CMD_TIMEOUT 100
-+#define CMD_REPLY_RETRY 5
-+
-+#define CX82310_MTU 1514
-+#define CMD_EP 0x01
-+
-+/*
-+ * execute control command
-+ * - optionally send some data (command parameters)
-+ * - optionally wait for the reply
-+ * - optionally read some data from the reply
-+ */
-+static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,
-+ u8 *wdata, int wlen, u8 *rdata, int rlen)
-+{
-+ int actual_len, retries, ret;
-+ struct usb_device *udev = dev->udev;
-+ u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL);
-+
-+ if (!buf)
-+ return -ENOMEM;
-+
-+ /* create command packet */
-+ buf[0] = cmd;
-+ if (wdata)
-+ memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4));
-+
-+ /* send command packet */
-+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,
-+ CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);
-+ if (ret < 0) {
-+ if (cmd != CMD_GET_LINK_STATUS)
-+ dev_err(&dev->udev->dev, "send command %#x: error %d\n",
-+ cmd, ret);
-+ goto end;
-+ }
-+
-+ if (reply) {
-+ /* wait for reply, retry if it's empty */
-+ for (retries = 0; retries < CMD_REPLY_RETRY; retries++) {
-+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP),
-+ buf, CMD_PACKET_SIZE, &actual_len,
-+ CMD_TIMEOUT);
-+ if (ret < 0) {
-+ if (cmd != CMD_GET_LINK_STATUS)
-+ dev_err(&dev->udev->dev,
-+ "reply receive error %d\n",
-+ ret);
-+ goto end;
-+ }
-+ if (actual_len > 0)
-+ break;
-+ }
-+ if (actual_len == 0) {
-+ dev_err(&dev->udev->dev, "no reply to command %#x\n",
-+ cmd);
-+ ret = -EIO;
-+ goto end;
-+ }
-+ if (buf[0] != cmd) {
-+ dev_err(&dev->udev->dev,
-+ "got reply to command %#x, expected: %#x\n",
-+ buf[0], cmd);
-+ ret = -EIO;
-+ goto end;
-+ }
-+ if (buf[1] != STATUS_SUCCESS) {
-+ dev_err(&dev->udev->dev, "command %#x failed: %#x\n",
-+ cmd, buf[1]);
-+ ret = -EIO;
-+ goto end;
-+ }
-+ if (rdata)
-+ memcpy(rdata, buf + 4,
-+ min_t(int, rlen, CMD_PACKET_SIZE - 4));
-+ }
-+end:
-+ kfree(buf);
-+ return ret;
-+}
-+
-+#define partial_len data[0] /* length of partial packet data */
-+#define partial_rem data[1] /* remaining (missing) data length */
-+#define partial_data data[2] /* partial packet data */
-+
-+static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret;
-+ char buf[15];
-+ struct usb_device *udev = dev->udev;
-+ u8 link[3];
-+ int timeout = 50;
-+
-+ /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */
-+ if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
-+ && strcmp(buf, "USB NET CARD")) {
-+ dev_info(&udev->dev, "ignoring: probably an ADSL modem\n");
-+ return -ENODEV;
-+ }
-+
-+ ret = usbnet_get_endpoints(dev, intf);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * this must not include ethernet header as the device can send partial
-+ * packets with no header (and sometimes even empty URBs)
-+ */
-+ dev->net->hard_header_len = 0;
-+ /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */
-+ dev->hard_mtu = CX82310_MTU + 2;
-+ /* we can receive URBs up to 4KB from the device */
-+ dev->rx_urb_size = 4096;
-+
-+ dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL);
-+ if (!dev->partial_data)
-+ return -ENOMEM;
-+
-+ /* wait for firmware to become ready (indicated by the link being up) */
-+ while (--timeout) {
-+ ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
-+ link, sizeof(link));
-+ /* the command can time out during boot - it's not an error */
-+ if (!ret && link[0] == 1 && link[2] == 1)
-+ break;
-+ msleep(500);
-+ }
-+ if (!timeout) {
-+ dev_err(&udev->dev, "firmware not ready in time\n");
-+ return -ETIMEDOUT;
-+ }
-+
-+ /* enable ethernet mode (?) */
-+ ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);
-+ if (ret) {
-+ dev_err(&udev->dev, "unable to enable ethernet mode: %d\n",
-+ ret);
-+ goto err;
-+ }
-+
-+ /* get the MAC address */
-+ ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0,
-+ dev->net->dev_addr, ETH_ALEN);
-+ if (ret) {
-+ dev_err(&udev->dev, "unable to read MAC address: %d\n", ret);
-+ goto err;
-+ }
-+
-+ /* start (does not seem to have any effect?) */
-+ ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0);
-+ if (ret)
-+ goto err;
-+
-+ return 0;
-+err:
-+ kfree((void *)dev->partial_data);
-+ return ret;
-+}
-+
-+static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ kfree((void *)dev->partial_data);
-+}
-+
-+/*
-+ * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte
-+ * packet length at the beginning.
-+ * The last packet might be incomplete (when it crosses the 4KB URB size),
-+ * continuing in the next skb (without any headers).
-+ * If a packet has odd length, there is one extra byte at the end (before next
-+ * packet or at the end of the URB).
-+ */
-+static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ int len;
-+ struct sk_buff *skb2;
-+
-+ /*
-+ * If the last skb ended with an incomplete packet, this skb contains
-+ * end of that packet at the beginning.
-+ */
-+ if (dev->partial_rem) {
-+ len = dev->partial_len + dev->partial_rem;
-+ skb2 = alloc_skb(len, GFP_ATOMIC);
-+ if (!skb2)
-+ return 0;
-+ skb_put(skb2, len);
-+ memcpy(skb2->data, (void *)dev->partial_data,
-+ dev->partial_len);
-+ memcpy(skb2->data + dev->partial_len, skb->data,
-+ dev->partial_rem);
-+ usbnet_skb_return(dev, skb2);
-+ skb_pull(skb, (dev->partial_rem + 1) & ~1);
-+ dev->partial_rem = 0;
-+ if (skb->len < 2)
-+ return 1;
-+ }
-+
-+ /* a skb can contain multiple packets */
-+ while (skb->len > 1) {
-+ /* first two bytes are packet length */
-+ len = skb->data[0] | (skb->data[1] << 8);
-+ skb_pull(skb, 2);
-+
-+ /* if last packet in the skb, let usbnet to process it */
-+ if (len == skb->len || len + 1 == skb->len) {
-+ skb_trim(skb, len);
-+ break;
-+ }
-+
-+ if (len > CX82310_MTU) {
-+ dev_err(&dev->udev->dev, "RX packet too long: %d B\n",
-+ len);
-+ return 0;
-+ }
-+
-+ /* incomplete packet, save it for the next skb */
-+ if (len > skb->len) {
-+ dev->partial_len = skb->len;
-+ dev->partial_rem = len - skb->len;
-+ memcpy((void *)dev->partial_data, skb->data,
-+ dev->partial_len);
-+ skb_pull(skb, skb->len);
-+ break;
-+ }
-+
-+ skb2 = alloc_skb(len, GFP_ATOMIC);
-+ if (!skb2)
-+ return 0;
-+ skb_put(skb2, len);
-+ memcpy(skb2->data, skb->data, len);
-+ /* process the packet */
-+ usbnet_skb_return(dev, skb2);
-+
-+ skb_pull(skb, (len + 1) & ~1);
-+ }
-+
-+ /* let usbnet process the last packet */
-+ return 1;
-+}
-+
-+/* TX is easy, just add 2 bytes of length at the beginning */
-+static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ int len = skb->len;
-+
-+ if (skb_headroom(skb) < 2) {
-+ struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+ skb_push(skb, 2);
-+
-+ skb->data[0] = len;
-+ skb->data[1] = len >> 8;
-+
-+ return skb;
-+}
-+
-+
-+static const struct driver_info cx82310_info = {
-+ .description = "Conexant CX82310 USB ethernet",
-+ .flags = FLAG_ETHER,
-+ .bind = cx82310_bind,
-+ .unbind = cx82310_unbind,
-+ .rx_fixup = cx82310_rx_fixup,
-+ .tx_fixup = cx82310_tx_fixup,
-+};
-+
-+#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \
-+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
-+ USB_DEVICE_ID_MATCH_DEV_INFO, \
-+ .idVendor = (vend), \
-+ .idProduct = (prod), \
-+ .bDeviceClass = (cl), \
-+ .bDeviceSubClass = (sc), \
-+ .bDeviceProtocol = (pr)
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),
-+ .driver_info = (unsigned long) &cx82310_info
-+ },
-+ { },
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver cx82310_driver = {
-+ .name = "cx82310_eth",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(cx82310_driver);
-+
-+MODULE_AUTHOR("Ondrej Zary");
-+MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/dm9601.c backports-4.2.6-1/drivers/net/usb/dm9601.c
---- backports-4.2.6-1.org/drivers/net/usb/dm9601.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/dm9601.c 2016-06-28 14:35:17.978640554 +0200
-@@ -0,0 +1,647 @@
-+/*
-+ * Davicom DM96xx USB 10/100Mbps ethernet devices
-+ *
-+ * Peter Korsgaard <jacmet@sunsite.dk>
-+ *
-+ * This file is licensed under the terms of the GNU General Public License
-+ * version 2. This program is licensed "as is" without any warranty of any
-+ * kind, whether express or implied.
-+ */
-+
-+//#define DEBUG
-+
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/stddef.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+
-+/* datasheet:
-+ http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf
-+*/
-+
-+/* control requests */
-+#define DM_READ_REGS 0x00
-+#define DM_WRITE_REGS 0x01
-+#define DM_READ_MEMS 0x02
-+#define DM_WRITE_REG 0x03
-+#define DM_WRITE_MEMS 0x05
-+#define DM_WRITE_MEM 0x07
-+
-+/* registers */
-+#define DM_NET_CTRL 0x00
-+#define DM_RX_CTRL 0x05
-+#define DM_SHARED_CTRL 0x0b
-+#define DM_SHARED_ADDR 0x0c
-+#define DM_SHARED_DATA 0x0d /* low + high */
-+#define DM_PHY_ADDR 0x10 /* 6 bytes */
-+#define DM_MCAST_ADDR 0x16 /* 8 bytes */
-+#define DM_GPR_CTRL 0x1e
-+#define DM_GPR_DATA 0x1f
-+#define DM_CHIP_ID 0x2c
-+#define DM_MODE_CTRL 0x91 /* only on dm9620 */
-+
-+/* chip id values */
-+#define ID_DM9601 0
-+#define ID_DM9620 1
-+
-+#define DM_MAX_MCAST 64
-+#define DM_MCAST_SIZE 8
-+#define DM_EEPROM_LEN 256
-+#define DM_TX_OVERHEAD 2 /* 2 byte header */
-+#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
-+#define DM_TIMEOUT 1000
-+
-+static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ int err;
-+ err = usbnet_read_cmd(dev, DM_READ_REGS,
-+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, reg, data, length);
-+ if(err != length && err >= 0)
-+ err = -EINVAL;
-+ return err;
-+}
-+
-+static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
-+{
-+ return dm_read(dev, reg, 1, value);
-+}
-+
-+static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ int err;
-+ err = usbnet_write_cmd(dev, DM_WRITE_REGS,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, reg, data, length);
-+
-+ if (err >= 0 && err < length)
-+ err = -EINVAL;
-+ return err;
-+}
-+
-+static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
-+{
-+ return usbnet_write_cmd(dev, DM_WRITE_REG,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, reg, NULL, 0);
-+}
-+
-+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ usbnet_write_cmd_async(dev, DM_WRITE_REGS,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, reg, data, length);
-+}
-+
-+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
-+{
-+ usbnet_write_cmd_async(dev, DM_WRITE_REG,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, reg, NULL, 0);
-+}
-+
-+static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
-+{
-+ int ret, i;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
-+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
-+
-+ for (i = 0; i < DM_TIMEOUT; i++) {
-+ u8 tmp = 0;
-+
-+ udelay(1);
-+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* ready */
-+ if ((tmp & 1) == 0)
-+ break;
-+ }
-+
-+ if (i == DM_TIMEOUT) {
-+ netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
-+ ret = dm_read(dev, DM_SHARED_DATA, 2, value);
-+
-+ netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
-+ phy, reg, *value, ret);
-+
-+ out:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
-+{
-+ int ret, i;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
-+ if (ret < 0)
-+ goto out;
-+
-+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
-+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
-+
-+ for (i = 0; i < DM_TIMEOUT; i++) {
-+ u8 tmp = 0;
-+
-+ udelay(1);
-+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* ready */
-+ if ((tmp & 1) == 0)
-+ break;
-+ }
-+
-+ if (i == DM_TIMEOUT) {
-+ netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
-+ ret = -EIO;
-+ goto out;
-+ }
-+
-+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
-+
-+out:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
-+{
-+ return dm_read_shared_word(dev, 0, offset, value);
-+}
-+
-+
-+
-+static int dm9601_get_eeprom_len(struct net_device *dev)
-+{
-+ return DM_EEPROM_LEN;
-+}
-+
-+static int dm9601_get_eeprom(struct net_device *net,
-+ struct ethtool_eeprom *eeprom, u8 * data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ __le16 *ebuf = (__le16 *) data;
-+ int i;
-+
-+ /* access is 16bit */
-+ if ((eeprom->offset % 2) || (eeprom->len % 2))
-+ return -EINVAL;
-+
-+ for (i = 0; i < eeprom->len / 2; i++) {
-+ if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
-+ &ebuf[i]) < 0)
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ __le16 res;
-+
-+ if (phy_id) {
-+ netdev_dbg(dev->net, "Only internal phy supported\n");
-+ return 0;
-+ }
-+
-+ dm_read_shared_word(dev, 1, loc, &res);
-+
-+ netdev_dbg(dev->net,
-+ "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
-+ phy_id, loc, le16_to_cpu(res));
-+
-+ return le16_to_cpu(res);
-+}
-+
-+static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
-+ int val)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 res = cpu_to_le16(val);
-+
-+ if (phy_id) {
-+ netdev_dbg(dev->net, "Only internal phy supported\n");
-+ return;
-+ }
-+
-+ netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
-+ phy_id, loc, val);
-+
-+ dm_write_shared_word(dev, 1, loc, res);
-+}
-+
-+static void dm9601_get_drvinfo(struct net_device *net,
-+ struct ethtool_drvinfo *info)
-+{
-+ /* Inherit standard device info */
-+ usbnet_get_drvinfo(net, info);
-+ info->eedump_len = DM_EEPROM_LEN;
-+}
-+
-+static u32 dm9601_get_link(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return mii_link_ok(&dev->mii);
-+}
-+
-+static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static const struct ethtool_ops dm9601_ethtool_ops = {
-+ .get_drvinfo = dm9601_get_drvinfo,
-+ .get_link = dm9601_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_eeprom_len = dm9601_get_eeprom_len,
-+ .get_eeprom = dm9601_get_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static void dm9601_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ /* We use the 20 byte dev->data for our 8 byte filter buffer
-+ * to avoid allocating memory that is tricky to free later */
-+ u8 *hashes = (u8 *) & dev->data;
-+ u8 rx_ctl = 0x31;
-+
-+ memset(hashes, 0x00, DM_MCAST_SIZE);
-+ hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
-+
-+ if (net->flags & IFF_PROMISC) {
-+ rx_ctl |= 0x02;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > DM_MAX_MCAST) {
-+ rx_ctl |= 0x08;
-+ } else if (!netdev_mc_empty(net)) {
-+ struct netdev_hw_addr *ha;
-+
-+ netdev_for_each_mc_addr(ha, net) {
-+ u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ hashes[crc >> 3] |= 1 << (crc & 0x7);
-+ }
-+ }
-+
-+ dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
-+ dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
-+}
-+
-+static void __dm9601_set_mac_address(struct usbnet *dev)
-+{
-+ dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
-+}
-+
-+static int dm9601_set_mac_address(struct net_device *net, void *p)
-+{
-+ struct sockaddr *addr = p;
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ if (!is_valid_ether_addr(addr->sa_data)) {
-+ dev_err(&net->dev, "not setting invalid mac address %pM\n",
-+ addr->sa_data);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(net->dev_addr, addr->sa_data, net->addr_len);
-+ __dm9601_set_mac_address(dev);
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops dm9601_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = dm9601_ioctl,
-+ .ndo_set_rx_mode = dm9601_set_multicast,
-+ .ndo_set_mac_address = dm9601_set_mac_address,
-+};
-+
-+static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret;
-+ u8 mac[ETH_ALEN], id;
-+
-+ ret = usbnet_get_endpoints(dev, intf);
-+ if (ret)
-+ goto out;
-+
-+ dev->net->netdev_ops = &dm9601_netdev_ops;
-+ dev->net->ethtool_ops = &dm9601_ethtool_ops;
-+ dev->net->hard_header_len += DM_TX_OVERHEAD;
-+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-+
-+ /* dm9620/21a require room for 4 byte padding, even in dm9601
-+ * mode, so we need +1 to be able to receive full size
-+ * ethernet frames.
-+ */
-+ dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1;
-+
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = dm9601_mdio_read;
-+ dev->mii.mdio_write = dm9601_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0x1f;
-+
-+ /* reset */
-+ dm_write_reg(dev, DM_NET_CTRL, 1);
-+ udelay(20);
-+
-+ /* read MAC */
-+ if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) {
-+ printk(KERN_ERR "Error reading MAC address\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ /*
-+ * Overwrite the auto-generated address only with good ones.
-+ */
-+ if (is_valid_ether_addr(mac))
-+ memcpy(dev->net->dev_addr, mac, ETH_ALEN);
-+ else {
-+ printk(KERN_WARNING
-+ "dm9601: No valid MAC address in EEPROM, using %pM\n",
-+ dev->net->dev_addr);
-+ __dm9601_set_mac_address(dev);
-+ }
-+
-+ if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) {
-+ netdev_err(dev->net, "Error reading chip ID\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ /* put dm9620 devices in dm9601 mode */
-+ if (id == ID_DM9620) {
-+ u8 mode;
-+
-+ if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) {
-+ netdev_err(dev->net, "Error reading MODE_CTRL\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+ dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f);
-+ }
-+
-+ /* power up phy */
-+ dm_write_reg(dev, DM_GPR_CTRL, 1);
-+ dm_write_reg(dev, DM_GPR_DATA, 0);
-+
-+ /* receive broadcast packets */
-+ dm9601_set_multicast(dev->net);
-+
-+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
-+ mii_nway_restart(&dev->mii);
-+
-+out:
-+ return ret;
-+}
-+
-+static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ u8 status;
-+ int len;
-+
-+ /* format:
-+ b1: rx status
-+ b2: packet length (incl crc) low
-+ b3: packet length (incl crc) high
-+ b4..n-4: packet data
-+ bn-3..bn: ethernet crc
-+ */
-+
-+ if (unlikely(skb->len < DM_RX_OVERHEAD)) {
-+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
-+ return 0;
-+ }
-+
-+ status = skb->data[0];
-+ len = (skb->data[1] | (skb->data[2] << 8)) - 4;
-+
-+ if (unlikely(status & 0xbf)) {
-+ if (status & 0x01) dev->net->stats.rx_fifo_errors++;
-+ if (status & 0x02) dev->net->stats.rx_crc_errors++;
-+ if (status & 0x04) dev->net->stats.rx_frame_errors++;
-+ if (status & 0x20) dev->net->stats.rx_missed_errors++;
-+ if (status & 0x90) dev->net->stats.rx_length_errors++;
-+ return 0;
-+ }
-+
-+ skb_pull(skb, 3);
-+ skb_trim(skb, len);
-+
-+ return 1;
-+}
-+
-+static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ int len, pad;
-+
-+ /* format:
-+ b1: packet length low
-+ b2: packet length high
-+ b3..n: packet data
-+ */
-+
-+ len = skb->len + DM_TX_OVERHEAD;
-+
-+ /* workaround for dm962x errata with tx fifo getting out of
-+ * sync if a USB bulk transfer retry happens right after a
-+ * packet with odd / maxpacket length by adding up to 3 bytes
-+ * padding.
-+ */
-+ while ((len & 1) || !(len % dev->maxpacket))
-+ len++;
-+
-+ len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
-+ pad = len - skb->len;
-+
-+ if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ __skb_push(skb, DM_TX_OVERHEAD);
-+
-+ if (pad) {
-+ memset(skb->data + skb->len, 0, pad);
-+ __skb_put(skb, pad);
-+ }
-+
-+ skb->data[0] = len;
-+ skb->data[1] = len >> 8;
-+
-+ return skb;
-+}
-+
-+static void dm9601_status(struct usbnet *dev, struct urb *urb)
-+{
-+ int link;
-+ u8 *buf;
-+
-+ /* format:
-+ b0: net status
-+ b1: tx status 1
-+ b2: tx status 2
-+ b3: rx status
-+ b4: rx overflow
-+ b5: rx count
-+ b6: tx count
-+ b7: gpr
-+ */
-+
-+ if (urb->actual_length < 8)
-+ return;
-+
-+ buf = urb->transfer_buffer;
-+
-+ link = !!(buf[0] & 0x40);
-+ if (netif_carrier_ok(dev->net) != link) {
-+ usbnet_link_change(dev, link, 1);
-+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
-+ }
-+}
-+
-+static int dm9601_link_reset(struct usbnet *dev)
-+{
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+
-+ netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
-+ ethtool_cmd_speed(&ecmd), ecmd.duplex);
-+
-+ return 0;
-+}
-+
-+static const struct driver_info dm9601_info = {
-+ .description = "Davicom DM96xx USB 10/100 Ethernet",
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .bind = dm9601_bind,
-+ .rx_fixup = dm9601_rx_fixup,
-+ .tx_fixup = dm9601_tx_fixup,
-+ .status = dm9601_status,
-+ .link_reset = dm9601_link_reset,
-+ .reset = dm9601_link_reset,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0fe6, 0x8101), /* DM9601 USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x9000), /* DM9000E */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x9621), /* DM9621A USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x9622), /* DM9622 USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x0269), /* DM962OA USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {
-+ USB_DEVICE(0x0a46, 0x1269), /* DM9621A USB to Fast Ethernet Adapter */
-+ .driver_info = (unsigned long)&dm9601_info,
-+ },
-+ {}, // END
-+};
-+
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver dm9601_driver = {
-+ .name = "dm9601",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(dm9601_driver);
-+
-+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
-+MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/gl620a.c backports-4.2.6-1/drivers/net/usb/gl620a.c
---- backports-4.2.6-1.org/drivers/net/usb/gl620a.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/gl620a.c 2016-06-28 14:35:17.978640554 +0200
-@@ -0,0 +1,242 @@
-+/*
-+ * GeneSys GL620USB-A based links
-+ * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
-+ * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+// #define DEBUG // error path messages, extra info
-+// #define VERBOSE // more; success messages
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/gfp.h>
-+
-+
-+/*
-+ * GeneSys GL620USB-A (www.genesyslogic.com.tw)
-+ *
-+ * ... should partially interop with the Win32 driver for this hardware.
-+ * The GeneSys docs imply there's some NDIS issue motivating this framing.
-+ *
-+ * Some info from GeneSys:
-+ * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
-+ * (Some cables, like the BAFO-100c, use the half duplex version.)
-+ * - For the full duplex model, the low bit of the version code says
-+ * which side is which ("left/right").
-+ * - For the half duplex type, a control/interrupt handshake settles
-+ * the transfer direction. (That's disabled here, partially coded.)
-+ * A control URB would block until other side writes an interrupt.
-+ *
-+ * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
-+ * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
-+ */
-+
-+// control msg write command
-+#define GENELINK_CONNECT_WRITE 0xF0
-+// interrupt pipe index
-+#define GENELINK_INTERRUPT_PIPE 0x03
-+// interrupt read buffer size
-+#define INTERRUPT_BUFSIZE 0x08
-+// interrupt pipe interval value
-+#define GENELINK_INTERRUPT_INTERVAL 0x10
-+// max transmit packet number per transmit
-+#define GL_MAX_TRANSMIT_PACKETS 32
-+// max packet length
-+#define GL_MAX_PACKET_LEN 1514
-+// max receive buffer size
-+#define GL_RCV_BUF_SIZE \
-+ (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
-+
-+struct gl_packet {
-+ __le32 packet_length;
-+ char packet_data [1];
-+};
-+
-+struct gl_header {
-+ __le32 packet_count;
-+ struct gl_packet packets;
-+};
-+
-+static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct gl_header *header;
-+ struct gl_packet *packet;
-+ struct sk_buff *gl_skb;
-+ u32 size;
-+ u32 count;
-+
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ header = (struct gl_header *) skb->data;
-+
-+ // get the packet count of the received skb
-+ count = le32_to_cpu(header->packet_count);
-+ if (count > GL_MAX_TRANSMIT_PACKETS) {
-+ netdev_dbg(dev->net,
-+ "genelink: invalid received packet count %u\n",
-+ count);
-+ return 0;
-+ }
-+
-+ // set the current packet pointer to the first packet
-+ packet = &header->packets;
-+
-+ // decrement the length for the packet count size 4 bytes
-+ skb_pull(skb, 4);
-+
-+ while (count > 1) {
-+ // get the packet length
-+ size = le32_to_cpu(packet->packet_length);
-+
-+ // this may be a broken packet
-+ if (size > GL_MAX_PACKET_LEN) {
-+ netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
-+ size);
-+ return 0;
-+ }
-+
-+ // allocate the skb for the individual packet
-+ gl_skb = alloc_skb(size, GFP_ATOMIC);
-+ if (gl_skb) {
-+
-+ // copy the packet data to the new skb
-+ memcpy(skb_put(gl_skb, size),
-+ packet->packet_data, size);
-+ usbnet_skb_return(dev, gl_skb);
-+ }
-+
-+ // advance to the next packet
-+ packet = (struct gl_packet *)&packet->packet_data[size];
-+ count--;
-+
-+ // shift the data pointer to the next gl_packet
-+ skb_pull(skb, size + 4);
-+ }
-+
-+ // skip the packet length field 4 bytes
-+ skb_pull(skb, 4);
-+
-+ if (skb->len > GL_MAX_PACKET_LEN) {
-+ netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
-+ skb->len);
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+static struct sk_buff *
-+genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
-+{
-+ int padlen;
-+ int length = skb->len;
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+ __le32 *packet_count;
-+ __le32 *packet_len;
-+
-+ // FIXME: magic numbers, bleech
-+ padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
-+
-+ if ((!skb_cloned(skb))
-+ && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
-+ if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
-+ skb->data = memmove(skb->head + (4 + 4*1),
-+ skb->data, skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ }
-+ } else {
-+ struct sk_buff *skb2;
-+ skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ // attach the packet count to the header
-+ packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
-+ packet_len = packet_count + 1;
-+
-+ *packet_count = cpu_to_le32(1);
-+ *packet_len = cpu_to_le32(length);
-+
-+ // add padding byte
-+ if ((skb->len % dev->maxpacket) == 0)
-+ skb_put(skb, 1);
-+
-+ return skb;
-+}
-+
-+static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ dev->hard_mtu = GL_RCV_BUF_SIZE;
-+ dev->net->hard_header_len += 4;
-+ dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
-+ dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
-+ return 0;
-+}
-+
-+static const struct driver_info genelink_info = {
-+ .description = "Genesys GeneLink",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT,
-+ .bind = genelink_bind,
-+ .rx_fixup = genelink_rx_fixup,
-+ .tx_fixup = genelink_tx_fixup,
-+
-+ .in = 1, .out = 2,
-+
-+#ifdef GENELINK_ACK
-+ .check_connect =genelink_check_connect,
-+#endif
-+};
-+
-+static const struct usb_device_id products [] = {
-+
-+{
-+ USB_DEVICE(0x05e3, 0x0502), // GL620USB-A
-+ .driver_info = (unsigned long) &genelink_info,
-+},
-+ /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB
-+ * that's half duplex, not currently supported
-+ */
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver gl620a_driver = {
-+ .name = "gl620a",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(gl620a_driver);
-+
-+MODULE_AUTHOR("Jiun-Jie Huang");
-+MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
-+MODULE_LICENSE("GPL");
-+
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/hso.c backports-4.2.6-1/drivers/net/usb/hso.c
---- backports-4.2.6-1.org/drivers/net/usb/hso.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/hso.c 2016-06-28 14:35:17.981973887 +0200
-@@ -0,0 +1,3322 @@
-+/******************************************************************************
-+ *
-+ * Driver for Option High Speed Mobile Devices.
-+ *
-+ * Copyright (C) 2008 Option International
-+ * Filip Aben <f.aben@option.com>
-+ * Denis Joseph Barrow <d.barow@option.com>
-+ * Jan Dumon <j.dumon@option.com>
-+ * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
-+ * <ajb@spheresystems.co.uk>
-+ * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
-+ * Copyright (C) 2008 Novell, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-+ * USA
-+ *
-+ *
-+ *****************************************************************************/
-+
-+/******************************************************************************
-+ *
-+ * Description of the device:
-+ *
-+ * Interface 0: Contains the IP network interface on the bulk end points.
-+ * The multiplexed serial ports are using the interrupt and
-+ * control endpoints.
-+ * Interrupt contains a bitmap telling which multiplexed
-+ * serialport needs servicing.
-+ *
-+ * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the
-+ * port is opened, as this have a huge impact on the network port
-+ * throughput.
-+ *
-+ * Interface 2: Standard modem interface - circuit switched interface, this
-+ * can be used to make a standard ppp connection however it
-+ * should not be used in conjunction with the IP network interface
-+ * enabled for USB performance reasons i.e. if using this set
-+ * ideally disable_net=1.
-+ *
-+ *****************************************************************************/
-+
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/netdevice.h>
-+#include <linux/module.h>
-+#include <linux/ethtool.h>
-+#include <linux/usb.h>
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+#include <linux/kmod.h>
-+#include <linux/rfkill.h>
-+#include <linux/ip.h>
-+#include <linux/uaccess.h>
-+#include <linux/usb/cdc.h>
-+#include <net/arp.h>
-+#include <asm/byteorder.h>
-+#include <linux/serial_core.h>
-+#include <linux/serial.h>
-+#include <asm/local.h>
-+
-+#define MOD_AUTHOR "Option Wireless"
-+#define MOD_DESCRIPTION "USB High Speed Option driver"
-+#define MOD_LICENSE "GPL"
-+
-+#define HSO_MAX_NET_DEVICES 10
-+#define HSO__MAX_MTU 2048
-+#define DEFAULT_MTU 1500
-+#define DEFAULT_MRU 1500
-+
-+#define CTRL_URB_RX_SIZE 1024
-+#define CTRL_URB_TX_SIZE 64
-+
-+#define BULK_URB_RX_SIZE 4096
-+#define BULK_URB_TX_SIZE 8192
-+
-+#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU
-+#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU
-+#define MUX_BULK_RX_BUF_COUNT 4
-+#define USB_TYPE_OPTION_VENDOR 0x20
-+
-+/* These definitions are used with the struct hso_net flags element */
-+/* - use *_bit operations on it. (bit indices not values.) */
-+#define HSO_NET_RUNNING 0
-+
-+#define HSO_NET_TX_TIMEOUT (HZ*10)
-+
-+#define HSO_SERIAL_MAGIC 0x48534f31
-+
-+/* Number of ttys to handle */
-+#define HSO_SERIAL_TTY_MINORS 256
-+
-+#define MAX_RX_URBS 2
-+
-+/*****************************************************************************/
-+/* Debugging functions */
-+/*****************************************************************************/
-+#define D__(lvl_, fmt, arg...) \
-+ do { \
-+ printk(lvl_ "[%d:%s]: " fmt "\n", \
-+ __LINE__, __func__, ## arg); \
-+ } while (0)
-+
-+#define D_(lvl, args...) \
-+ do { \
-+ if (lvl & debug) \
-+ D__(KERN_INFO, args); \
-+ } while (0)
-+
-+#define D1(args...) D_(0x01, ##args)
-+#define D2(args...) D_(0x02, ##args)
-+#define D3(args...) D_(0x04, ##args)
-+#define D4(args...) D_(0x08, ##args)
-+#define D5(args...) D_(0x10, ##args)
-+
-+/*****************************************************************************/
-+/* Enumerators */
-+/*****************************************************************************/
-+enum pkt_parse_state {
-+ WAIT_IP,
-+ WAIT_DATA,
-+ WAIT_SYNC
-+};
-+
-+/*****************************************************************************/
-+/* Structs */
-+/*****************************************************************************/
-+
-+struct hso_shared_int {
-+ struct usb_endpoint_descriptor *intr_endp;
-+ void *shared_intr_buf;
-+ struct urb *shared_intr_urb;
-+ struct usb_device *usb;
-+ int use_count;
-+ int ref_count;
-+ struct mutex shared_int_lock;
-+};
-+
-+struct hso_net {
-+ struct hso_device *parent;
-+ struct net_device *net;
-+ struct rfkill *rfkill;
-+ char name[24];
-+
-+ struct usb_endpoint_descriptor *in_endp;
-+ struct usb_endpoint_descriptor *out_endp;
-+
-+ struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT];
-+ struct urb *mux_bulk_tx_urb;
-+ void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT];
-+ void *mux_bulk_tx_buf;
-+
-+ struct sk_buff *skb_rx_buf;
-+ struct sk_buff *skb_tx_buf;
-+
-+ enum pkt_parse_state rx_parse_state;
-+ spinlock_t net_lock;
-+
-+ unsigned short rx_buf_size;
-+ unsigned short rx_buf_missing;
-+ struct iphdr rx_ip_hdr;
-+
-+ unsigned long flags;
-+};
-+
-+enum rx_ctrl_state{
-+ RX_IDLE,
-+ RX_SENT,
-+ RX_PENDING
-+};
-+
-+#define BM_REQUEST_TYPE (0xa1)
-+#define B_NOTIFICATION (0x20)
-+#define W_VALUE (0x0)
-+#define W_LENGTH (0x2)
-+
-+#define B_OVERRUN (0x1<<6)
-+#define B_PARITY (0x1<<5)
-+#define B_FRAMING (0x1<<4)
-+#define B_RING_SIGNAL (0x1<<3)
-+#define B_BREAK (0x1<<2)
-+#define B_TX_CARRIER (0x1<<1)
-+#define B_RX_CARRIER (0x1<<0)
-+
-+struct hso_serial_state_notification {
-+ u8 bmRequestType;
-+ u8 bNotification;
-+ u16 wValue;
-+ u16 wIndex;
-+ u16 wLength;
-+ u16 UART_state_bitmap;
-+} __packed;
-+
-+struct hso_tiocmget {
-+ struct mutex mutex;
-+ wait_queue_head_t waitq;
-+ int intr_completed;
-+ struct usb_endpoint_descriptor *endp;
-+ struct urb *urb;
-+ struct hso_serial_state_notification serial_state_notification;
-+ u16 prev_UART_state_bitmap;
-+ struct uart_icount icount;
-+};
-+
-+
-+struct hso_serial {
-+ struct hso_device *parent;
-+ int magic;
-+ u8 minor;
-+
-+ struct hso_shared_int *shared_int;
-+
-+ /* rx/tx urb could be either a bulk urb or a control urb depending
-+ on which serial port it is used on. */
-+ struct urb *rx_urb[MAX_RX_URBS];
-+ u8 num_rx_urbs;
-+ u8 *rx_data[MAX_RX_URBS];
-+ u16 rx_data_length; /* should contain allocated length */
-+
-+ struct urb *tx_urb;
-+ u8 *tx_data;
-+ u8 *tx_buffer;
-+ u16 tx_data_length; /* should contain allocated length */
-+ u16 tx_data_count;
-+ u16 tx_buffer_count;
-+ struct usb_ctrlrequest ctrl_req_tx;
-+ struct usb_ctrlrequest ctrl_req_rx;
-+
-+ struct usb_endpoint_descriptor *in_endp;
-+ struct usb_endpoint_descriptor *out_endp;
-+
-+ enum rx_ctrl_state rx_state;
-+ u8 rts_state;
-+ u8 dtr_state;
-+ unsigned tx_urb_used:1;
-+
-+ struct tty_port port;
-+ /* from usb_serial_port */
-+ spinlock_t serial_lock;
-+
-+ int (*write_data) (struct hso_serial *serial);
-+ struct hso_tiocmget *tiocmget;
-+ /* Hacks required to get flow control
-+ * working on the serial receive buffers
-+ * so as not to drop characters on the floor.
-+ */
-+ int curr_rx_urb_idx;
-+ u8 rx_urb_filled[MAX_RX_URBS];
-+ struct tasklet_struct unthrottle_tasklet;
-+};
-+
-+struct hso_device {
-+ union {
-+ struct hso_serial *dev_serial;
-+ struct hso_net *dev_net;
-+ } port_data;
-+
-+ u32 port_spec;
-+
-+ u8 is_active;
-+ u8 usb_gone;
-+ struct work_struct async_get_intf;
-+ struct work_struct async_put_intf;
-+
-+ struct usb_device *usb;
-+ struct usb_interface *interface;
-+
-+ struct device *dev;
-+ struct kref ref;
-+ struct mutex mutex;
-+};
-+
-+/* Type of interface */
-+#define HSO_INTF_MASK 0xFF00
-+#define HSO_INTF_MUX 0x0100
-+#define HSO_INTF_BULK 0x0200
-+
-+/* Type of port */
-+#define HSO_PORT_MASK 0xFF
-+#define HSO_PORT_NO_PORT 0x0
-+#define HSO_PORT_CONTROL 0x1
-+#define HSO_PORT_APP 0x2
-+#define HSO_PORT_GPS 0x3
-+#define HSO_PORT_PCSC 0x4
-+#define HSO_PORT_APP2 0x5
-+#define HSO_PORT_GPS_CONTROL 0x6
-+#define HSO_PORT_MSD 0x7
-+#define HSO_PORT_VOICE 0x8
-+#define HSO_PORT_DIAG2 0x9
-+#define HSO_PORT_DIAG 0x10
-+#define HSO_PORT_MODEM 0x11
-+#define HSO_PORT_NETWORK 0x12
-+
-+/* Additional device info */
-+#define HSO_INFO_MASK 0xFF000000
-+#define HSO_INFO_CRC_BUG 0x01000000
-+
-+/*****************************************************************************/
-+/* Prototypes */
-+/*****************************************************************************/
-+/* Serial driver functions */
-+static int hso_serial_tiocmset(struct tty_struct *tty,
-+ unsigned int set, unsigned int clear);
-+static void ctrl_callback(struct urb *urb);
-+static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial);
-+static void hso_kick_transmit(struct hso_serial *serial);
-+/* Helper functions */
-+static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int,
-+ struct usb_device *usb, gfp_t gfp);
-+static void handle_usb_error(int status, const char *function,
-+ struct hso_device *hso_dev);
-+static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
-+ int type, int dir);
-+static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports);
-+static void hso_free_interface(struct usb_interface *intf);
-+static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags);
-+static int hso_stop_serial_device(struct hso_device *hso_dev);
-+static int hso_start_net_device(struct hso_device *hso_dev);
-+static void hso_free_shared_int(struct hso_shared_int *shared_int);
-+static int hso_stop_net_device(struct hso_device *hso_dev);
-+static void hso_serial_ref_free(struct kref *ref);
-+static void hso_std_serial_read_bulk_callback(struct urb *urb);
-+static int hso_mux_serial_read(struct hso_serial *serial);
-+static void async_get_intf(struct work_struct *data);
-+static void async_put_intf(struct work_struct *data);
-+static int hso_put_activity(struct hso_device *hso_dev);
-+static int hso_get_activity(struct hso_device *hso_dev);
-+static void tiocmget_intr_callback(struct urb *urb);
-+/*****************************************************************************/
-+/* Helping functions */
-+/*****************************************************************************/
-+
-+/* #define DEBUG */
-+
-+static inline struct hso_net *dev2net(struct hso_device *hso_dev)
-+{
-+ return hso_dev->port_data.dev_net;
-+}
-+
-+static inline struct hso_serial *dev2ser(struct hso_device *hso_dev)
-+{
-+ return hso_dev->port_data.dev_serial;
-+}
-+
-+/* Debugging functions */
-+#ifdef DEBUG
-+static void dbg_dump(int line_count, const char *func_name, unsigned char *buf,
-+ unsigned int len)
-+{
-+ static char name[255];
-+
-+ sprintf(name, "hso[%d:%s]", line_count, func_name);
-+ print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len);
-+}
-+
-+#define DUMP(buf_, len_) \
-+ dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_)
-+
-+#define DUMP1(buf_, len_) \
-+ do { \
-+ if (0x01 & debug) \
-+ DUMP(buf_, len_); \
-+ } while (0)
-+#else
-+#define DUMP(buf_, len_)
-+#define DUMP1(buf_, len_)
-+#endif
-+
-+/* module parameters */
-+static int debug;
-+static int tty_major;
-+static int disable_net;
-+
-+/* driver info */
-+static const char driver_name[] = "hso";
-+static const char tty_filename[] = "ttyHS";
-+static const char *version = __FILE__ ": " MOD_AUTHOR;
-+/* the usb driver itself (registered in hso_init) */
-+static struct usb_driver hso_driver;
-+/* serial structures */
-+static struct tty_driver *tty_drv;
-+static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS];
-+static struct hso_device *network_table[HSO_MAX_NET_DEVICES];
-+static spinlock_t serial_table_lock;
-+
-+static const s32 default_port_spec[] = {
-+ HSO_INTF_MUX | HSO_PORT_NETWORK,
-+ HSO_INTF_BULK | HSO_PORT_DIAG,
-+ HSO_INTF_BULK | HSO_PORT_MODEM,
-+ 0
-+};
-+
-+static const s32 icon321_port_spec[] = {
-+ HSO_INTF_MUX | HSO_PORT_NETWORK,
-+ HSO_INTF_BULK | HSO_PORT_DIAG2,
-+ HSO_INTF_BULK | HSO_PORT_MODEM,
-+ HSO_INTF_BULK | HSO_PORT_DIAG,
-+ 0
-+};
-+
-+#define default_port_device(vendor, product) \
-+ USB_DEVICE(vendor, product), \
-+ .driver_info = (kernel_ulong_t)default_port_spec
-+
-+#define icon321_port_device(vendor, product) \
-+ USB_DEVICE(vendor, product), \
-+ .driver_info = (kernel_ulong_t)icon321_port_spec
-+
-+/* list of devices we support */
-+static const struct usb_device_id hso_ids[] = {
-+ {default_port_device(0x0af0, 0x6711)},
-+ {default_port_device(0x0af0, 0x6731)},
-+ {default_port_device(0x0af0, 0x6751)},
-+ {default_port_device(0x0af0, 0x6771)},
-+ {default_port_device(0x0af0, 0x6791)},
-+ {default_port_device(0x0af0, 0x6811)},
-+ {default_port_device(0x0af0, 0x6911)},
-+ {default_port_device(0x0af0, 0x6951)},
-+ {default_port_device(0x0af0, 0x6971)},
-+ {default_port_device(0x0af0, 0x7011)},
-+ {default_port_device(0x0af0, 0x7031)},
-+ {default_port_device(0x0af0, 0x7051)},
-+ {default_port_device(0x0af0, 0x7071)},
-+ {default_port_device(0x0af0, 0x7111)},
-+ {default_port_device(0x0af0, 0x7211)},
-+ {default_port_device(0x0af0, 0x7251)},
-+ {default_port_device(0x0af0, 0x7271)},
-+ {default_port_device(0x0af0, 0x7311)},
-+ {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */
-+ {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */
-+ {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */
-+ {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */
-+ {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */
-+ {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */
-+ {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */
-+ {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */
-+ {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */
-+ {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */
-+ {USB_DEVICE(0x0af0, 0x7701)},
-+ {USB_DEVICE(0x0af0, 0x7706)},
-+ {USB_DEVICE(0x0af0, 0x7801)},
-+ {USB_DEVICE(0x0af0, 0x7901)},
-+ {USB_DEVICE(0x0af0, 0x7A01)},
-+ {USB_DEVICE(0x0af0, 0x7A05)},
-+ {USB_DEVICE(0x0af0, 0x8200)},
-+ {USB_DEVICE(0x0af0, 0x8201)},
-+ {USB_DEVICE(0x0af0, 0x8300)},
-+ {USB_DEVICE(0x0af0, 0x8302)},
-+ {USB_DEVICE(0x0af0, 0x8304)},
-+ {USB_DEVICE(0x0af0, 0x8400)},
-+ {USB_DEVICE(0x0af0, 0x8600)},
-+ {USB_DEVICE(0x0af0, 0x8800)},
-+ {USB_DEVICE(0x0af0, 0x8900)},
-+ {USB_DEVICE(0x0af0, 0x9000)},
-+ {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */
-+ {USB_DEVICE(0x0af0, 0xd035)},
-+ {USB_DEVICE(0x0af0, 0xd055)},
-+ {USB_DEVICE(0x0af0, 0xd155)},
-+ {USB_DEVICE(0x0af0, 0xd255)},
-+ {USB_DEVICE(0x0af0, 0xd057)},
-+ {USB_DEVICE(0x0af0, 0xd157)},
-+ {USB_DEVICE(0x0af0, 0xd257)},
-+ {USB_DEVICE(0x0af0, 0xd357)},
-+ {USB_DEVICE(0x0af0, 0xd058)},
-+ {USB_DEVICE(0x0af0, 0xc100)},
-+ {}
-+};
-+MODULE_DEVICE_TABLE(usb, hso_ids);
-+
-+/* Sysfs attribute */
-+static ssize_t hso_sysfs_show_porttype(struct device *dev,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct hso_device *hso_dev = dev_get_drvdata(dev);
-+ char *port_name;
-+
-+ if (!hso_dev)
-+ return 0;
-+
-+ switch (hso_dev->port_spec & HSO_PORT_MASK) {
-+ case HSO_PORT_CONTROL:
-+ port_name = "Control";
-+ break;
-+ case HSO_PORT_APP:
-+ port_name = "Application";
-+ break;
-+ case HSO_PORT_APP2:
-+ port_name = "Application2";
-+ break;
-+ case HSO_PORT_GPS:
-+ port_name = "GPS";
-+ break;
-+ case HSO_PORT_GPS_CONTROL:
-+ port_name = "GPS Control";
-+ break;
-+ case HSO_PORT_PCSC:
-+ port_name = "PCSC";
-+ break;
-+ case HSO_PORT_DIAG:
-+ port_name = "Diagnostic";
-+ break;
-+ case HSO_PORT_DIAG2:
-+ port_name = "Diagnostic2";
-+ break;
-+ case HSO_PORT_MODEM:
-+ port_name = "Modem";
-+ break;
-+ case HSO_PORT_NETWORK:
-+ port_name = "Network";
-+ break;
-+ default:
-+ port_name = "Unknown";
-+ break;
-+ }
-+
-+ return sprintf(buf, "%s\n", port_name);
-+}
-+static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL);
-+
-+static struct attribute *hso_serial_dev_attrs[] = {
-+ &dev_attr_hsotype.attr,
-+ NULL
-+};
-+
-+ATTRIBUTE_GROUPS(hso_serial_dev);
-+
-+static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb)
-+{
-+ int idx;
-+
-+ for (idx = 0; idx < serial->num_rx_urbs; idx++)
-+ if (serial->rx_urb[idx] == urb)
-+ return idx;
-+ dev_err(serial->parent->dev, "hso_urb_to_index failed\n");
-+ return -1;
-+}
-+
-+/* converts mux value to a port spec value */
-+static u32 hso_mux_to_port(int mux)
-+{
-+ u32 result;
-+
-+ switch (mux) {
-+ case 0x1:
-+ result = HSO_PORT_CONTROL;
-+ break;
-+ case 0x2:
-+ result = HSO_PORT_APP;
-+ break;
-+ case 0x4:
-+ result = HSO_PORT_PCSC;
-+ break;
-+ case 0x8:
-+ result = HSO_PORT_GPS;
-+ break;
-+ case 0x10:
-+ result = HSO_PORT_APP2;
-+ break;
-+ default:
-+ result = HSO_PORT_NO_PORT;
-+ }
-+ return result;
-+}
-+
-+/* converts port spec value to a mux value */
-+static u32 hso_port_to_mux(int port)
-+{
-+ u32 result;
-+
-+ switch (port & HSO_PORT_MASK) {
-+ case HSO_PORT_CONTROL:
-+ result = 0x0;
-+ break;
-+ case HSO_PORT_APP:
-+ result = 0x1;
-+ break;
-+ case HSO_PORT_PCSC:
-+ result = 0x2;
-+ break;
-+ case HSO_PORT_GPS:
-+ result = 0x3;
-+ break;
-+ case HSO_PORT_APP2:
-+ result = 0x4;
-+ break;
-+ default:
-+ result = 0x0;
-+ }
-+ return result;
-+}
-+
-+static struct hso_serial *get_serial_by_shared_int_and_type(
-+ struct hso_shared_int *shared_int,
-+ int mux)
-+{
-+ int i, port;
-+
-+ port = hso_mux_to_port(mux);
-+
-+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
-+ if (serial_table[i] &&
-+ (dev2ser(serial_table[i])->shared_int == shared_int) &&
-+ ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) {
-+ return dev2ser(serial_table[i]);
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static struct hso_serial *get_serial_by_index(unsigned index)
-+{
-+ struct hso_serial *serial = NULL;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&serial_table_lock, flags);
-+ if (serial_table[index])
-+ serial = dev2ser(serial_table[index]);
-+ spin_unlock_irqrestore(&serial_table_lock, flags);
-+
-+ return serial;
-+}
-+
-+static int get_free_serial_index(void)
-+{
-+ int index;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&serial_table_lock, flags);
-+ for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) {
-+ if (serial_table[index] == NULL) {
-+ spin_unlock_irqrestore(&serial_table_lock, flags);
-+ return index;
-+ }
-+ }
-+ spin_unlock_irqrestore(&serial_table_lock, flags);
-+
-+ printk(KERN_ERR "%s: no free serial devices in table\n", __func__);
-+ return -1;
-+}
-+
-+static void set_serial_by_index(unsigned index, struct hso_serial *serial)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&serial_table_lock, flags);
-+ if (serial)
-+ serial_table[index] = serial->parent;
-+ else
-+ serial_table[index] = NULL;
-+ spin_unlock_irqrestore(&serial_table_lock, flags);
-+}
-+
-+static void handle_usb_error(int status, const char *function,
-+ struct hso_device *hso_dev)
-+{
-+ char *explanation;
-+
-+ switch (status) {
-+ case -ENODEV:
-+ explanation = "no device";
-+ break;
-+ case -ENOENT:
-+ explanation = "endpoint not enabled";
-+ break;
-+ case -EPIPE:
-+ explanation = "endpoint stalled";
-+ break;
-+ case -ENOSPC:
-+ explanation = "not enough bandwidth";
-+ break;
-+ case -ESHUTDOWN:
-+ explanation = "device disabled";
-+ break;
-+ case -EHOSTUNREACH:
-+ explanation = "device suspended";
-+ break;
-+ case -EINVAL:
-+ case -EAGAIN:
-+ case -EFBIG:
-+ case -EMSGSIZE:
-+ explanation = "internal error";
-+ break;
-+ case -EILSEQ:
-+ case -EPROTO:
-+ case -ETIME:
-+ case -ETIMEDOUT:
-+ explanation = "protocol error";
-+ if (hso_dev)
-+ usb_queue_reset_device(hso_dev->interface);
-+ break;
-+ default:
-+ explanation = "unknown status";
-+ break;
-+ }
-+
-+ /* log a meaningful explanation of an USB status */
-+ D1("%s: received USB status - %s (%d)", function, explanation, status);
-+}
-+
-+/* Network interface functions */
-+
-+/* called when net interface is brought up by ifconfig */
-+static int hso_net_open(struct net_device *net)
-+{
-+ struct hso_net *odev = netdev_priv(net);
-+ unsigned long flags = 0;
-+
-+ if (!odev) {
-+ dev_err(&net->dev, "No net device !\n");
-+ return -ENODEV;
-+ }
-+
-+ odev->skb_tx_buf = NULL;
-+
-+ /* setup environment */
-+ spin_lock_irqsave(&odev->net_lock, flags);
-+ odev->rx_parse_state = WAIT_IP;
-+ odev->rx_buf_size = 0;
-+ odev->rx_buf_missing = sizeof(struct iphdr);
-+ spin_unlock_irqrestore(&odev->net_lock, flags);
-+
-+ /* We are up and running. */
-+ set_bit(HSO_NET_RUNNING, &odev->flags);
-+ hso_start_net_device(odev->parent);
-+
-+ /* Tell the kernel we are ready to start receiving from it */
-+ netif_start_queue(net);
-+
-+ return 0;
-+}
-+
-+/* called when interface is brought down by ifconfig */
-+static int hso_net_close(struct net_device *net)
-+{
-+ struct hso_net *odev = netdev_priv(net);
-+
-+ /* we don't need the queue anymore */
-+ netif_stop_queue(net);
-+ /* no longer running */
-+ clear_bit(HSO_NET_RUNNING, &odev->flags);
-+
-+ hso_stop_net_device(odev->parent);
-+
-+ /* done */
-+ return 0;
-+}
-+
-+/* USB tells is xmit done, we should start the netqueue again */
-+static void write_bulk_callback(struct urb *urb)
-+{
-+ struct hso_net *odev = urb->context;
-+ int status = urb->status;
-+
-+ /* Sanity check */
-+ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) {
-+ dev_err(&urb->dev->dev, "%s: device not running\n", __func__);
-+ return;
-+ }
-+
-+ /* Do we still have a valid kernel network device? */
-+ if (!netif_device_present(odev->net)) {
-+ dev_err(&urb->dev->dev, "%s: net device not present\n",
-+ __func__);
-+ return;
-+ }
-+
-+ /* log status, but don't act on it, we don't need to resubmit anything
-+ * anyhow */
-+ if (status)
-+ handle_usb_error(status, __func__, odev->parent);
-+
-+ hso_put_activity(odev->parent);
-+
-+ /* Tell the network interface we are ready for another frame */
-+ netif_wake_queue(odev->net);
-+}
-+
-+/* called by kernel when we need to transmit a packet */
-+static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb,
-+ struct net_device *net)
-+{
-+ struct hso_net *odev = netdev_priv(net);
-+ int result;
-+
-+ /* Tell the kernel, "No more frames 'til we are done with this one." */
-+ netif_stop_queue(net);
-+ if (hso_get_activity(odev->parent) == -EAGAIN) {
-+ odev->skb_tx_buf = skb;
-+ return NETDEV_TX_OK;
-+ }
-+
-+ /* log if asked */
-+ DUMP1(skb->data, skb->len);
-+ /* Copy it from kernel memory to OUR memory */
-+ memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len);
-+ D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE);
-+
-+ /* Fill in the URB for shipping it out. */
-+ usb_fill_bulk_urb(odev->mux_bulk_tx_urb,
-+ odev->parent->usb,
-+ usb_sndbulkpipe(odev->parent->usb,
-+ odev->out_endp->
-+ bEndpointAddress & 0x7F),
-+ odev->mux_bulk_tx_buf, skb->len, write_bulk_callback,
-+ odev);
-+
-+ /* Deal with the Zero Length packet problem, I hope */
-+ odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET;
-+
-+ /* Send the URB on its merry way. */
-+ result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC);
-+ if (result) {
-+ dev_warn(&odev->parent->interface->dev,
-+ "failed mux_bulk_tx_urb %d\n", result);
-+ net->stats.tx_errors++;
-+ netif_start_queue(net);
-+ } else {
-+ net->stats.tx_packets++;
-+ net->stats.tx_bytes += skb->len;
-+ }
-+ dev_kfree_skb(skb);
-+ /* we're done */
-+ return NETDEV_TX_OK;
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_link = ethtool_op_get_link
-+};
-+
-+/* called when a packet did not ack after watchdogtimeout */
-+static void hso_net_tx_timeout(struct net_device *net)
-+{
-+ struct hso_net *odev = netdev_priv(net);
-+
-+ if (!odev)
-+ return;
-+
-+ /* Tell syslog we are hosed. */
-+ dev_warn(&net->dev, "Tx timed out.\n");
-+
-+ /* Tear the waiting frame off the list */
-+ if (odev->mux_bulk_tx_urb &&
-+ (odev->mux_bulk_tx_urb->status == -EINPROGRESS))
-+ usb_unlink_urb(odev->mux_bulk_tx_urb);
-+
-+ /* Update statistics */
-+ net->stats.tx_errors++;
-+}
-+
-+/* make a real packet from the received USB buffer */
-+static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
-+ unsigned int count, unsigned char is_eop)
-+{
-+ unsigned short temp_bytes;
-+ unsigned short buffer_offset = 0;
-+ unsigned short frame_len;
-+ unsigned char *tmp_rx_buf;
-+
-+ /* log if needed */
-+ D1("Rx %d bytes", count);
-+ DUMP(ip_pkt, min(128, (int)count));
-+
-+ while (count) {
-+ switch (odev->rx_parse_state) {
-+ case WAIT_IP:
-+ /* waiting for IP header. */
-+ /* wanted bytes - size of ip header */
-+ temp_bytes =
-+ (count <
-+ odev->rx_buf_missing) ? count : odev->
-+ rx_buf_missing;
-+
-+ memcpy(((unsigned char *)(&odev->rx_ip_hdr)) +
-+ odev->rx_buf_size, ip_pkt + buffer_offset,
-+ temp_bytes);
-+
-+ odev->rx_buf_size += temp_bytes;
-+ buffer_offset += temp_bytes;
-+ odev->rx_buf_missing -= temp_bytes;
-+ count -= temp_bytes;
-+
-+ if (!odev->rx_buf_missing) {
-+ /* header is complete allocate an sk_buffer and
-+ * continue to WAIT_DATA */
-+ frame_len = ntohs(odev->rx_ip_hdr.tot_len);
-+
-+ if ((frame_len > DEFAULT_MRU) ||
-+ (frame_len < sizeof(struct iphdr))) {
-+ dev_err(&odev->net->dev,
-+ "Invalid frame (%d) length\n",
-+ frame_len);
-+ odev->rx_parse_state = WAIT_SYNC;
-+ continue;
-+ }
-+ /* Allocate an sk_buff */
-+ odev->skb_rx_buf = netdev_alloc_skb(odev->net,
-+ frame_len);
-+ if (!odev->skb_rx_buf) {
-+ /* We got no receive buffer. */
-+ D1("could not allocate memory");
-+ odev->rx_parse_state = WAIT_SYNC;
-+ continue;
-+ }
-+
-+ /* Copy what we got so far. make room for iphdr
-+ * after tail. */
-+ tmp_rx_buf =
-+ skb_put(odev->skb_rx_buf,
-+ sizeof(struct iphdr));
-+ memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr),
-+ sizeof(struct iphdr));
-+
-+ /* ETH_HLEN */
-+ odev->rx_buf_size = sizeof(struct iphdr);
-+
-+ /* Filip actually use .tot_len */
-+ odev->rx_buf_missing =
-+ frame_len - sizeof(struct iphdr);
-+ odev->rx_parse_state = WAIT_DATA;
-+ }
-+ break;
-+
-+ case WAIT_DATA:
-+ temp_bytes = (count < odev->rx_buf_missing)
-+ ? count : odev->rx_buf_missing;
-+
-+ /* Copy the rest of the bytes that are left in the
-+ * buffer into the waiting sk_buf. */
-+ /* Make room for temp_bytes after tail. */
-+ tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes);
-+ memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes);
-+
-+ odev->rx_buf_missing -= temp_bytes;
-+ count -= temp_bytes;
-+ buffer_offset += temp_bytes;
-+ odev->rx_buf_size += temp_bytes;
-+ if (!odev->rx_buf_missing) {
-+ /* Packet is complete. Inject into stack. */
-+ /* We have IP packet here */
-+ odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP);
-+ skb_reset_mac_header(odev->skb_rx_buf);
-+
-+ /* Ship it off to the kernel */
-+ netif_rx(odev->skb_rx_buf);
-+ /* No longer our buffer. */
-+ odev->skb_rx_buf = NULL;
-+
-+ /* update out statistics */
-+ odev->net->stats.rx_packets++;
-+
-+ odev->net->stats.rx_bytes += odev->rx_buf_size;
-+
-+ odev->rx_buf_size = 0;
-+ odev->rx_buf_missing = sizeof(struct iphdr);
-+ odev->rx_parse_state = WAIT_IP;
-+ }
-+ break;
-+
-+ case WAIT_SYNC:
-+ D1(" W_S");
-+ count = 0;
-+ break;
-+ default:
-+ D1(" ");
-+ count--;
-+ break;
-+ }
-+ }
-+
-+ /* Recovery mechanism for WAIT_SYNC state. */
-+ if (is_eop) {
-+ if (odev->rx_parse_state == WAIT_SYNC) {
-+ odev->rx_parse_state = WAIT_IP;
-+ odev->rx_buf_size = 0;
-+ odev->rx_buf_missing = sizeof(struct iphdr);
-+ }
-+ }
-+}
-+
-+static void fix_crc_bug(struct urb *urb, __le16 max_packet_size)
-+{
-+ static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
-+ u32 rest = urb->actual_length % le16_to_cpu(max_packet_size);
-+
-+ if (((rest == 5) || (rest == 6)) &&
-+ !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4,
-+ crc_check, 4)) {
-+ urb->actual_length -= 4;
-+ }
-+}
-+
-+/* Moving data from usb to kernel (in interrupt state) */
-+static void read_bulk_callback(struct urb *urb)
-+{
-+ struct hso_net *odev = urb->context;
-+ struct net_device *net;
-+ int result;
-+ int status = urb->status;
-+
-+ /* is al ok? (Filip: Who's Al ?) */
-+ if (status) {
-+ handle_usb_error(status, __func__, odev->parent);
-+ return;
-+ }
-+
-+ /* Sanity check */
-+ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) {
-+ D1("BULK IN callback but driver is not active!");
-+ return;
-+ }
-+ usb_mark_last_busy(urb->dev);
-+
-+ net = odev->net;
-+
-+ if (!netif_device_present(net)) {
-+ /* Somebody killed our network interface... */
-+ return;
-+ }
-+
-+ if (odev->parent->port_spec & HSO_INFO_CRC_BUG)
-+ fix_crc_bug(urb, odev->in_endp->wMaxPacketSize);
-+
-+ /* do we even have a packet? */
-+ if (urb->actual_length) {
-+ /* Handle the IP stream, add header and push it onto network
-+ * stack if the packet is complete. */
-+ spin_lock(&odev->net_lock);
-+ packetizeRx(odev, urb->transfer_buffer, urb->actual_length,
-+ (urb->transfer_buffer_length >
-+ urb->actual_length) ? 1 : 0);
-+ spin_unlock(&odev->net_lock);
-+ }
-+
-+ /* We are done with this URB, resubmit it. Prep the USB to wait for
-+ * another frame. Reuse same as received. */
-+ usb_fill_bulk_urb(urb,
-+ odev->parent->usb,
-+ usb_rcvbulkpipe(odev->parent->usb,
-+ odev->in_endp->
-+ bEndpointAddress & 0x7F),
-+ urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE,
-+ read_bulk_callback, odev);
-+
-+ /* Give this to the USB subsystem so it can tell us when more data
-+ * arrives. */
-+ result = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (result)
-+ dev_warn(&odev->parent->interface->dev,
-+ "%s failed submit mux_bulk_rx_urb %d\n", __func__,
-+ result);
-+}
-+
-+/* Serial driver functions */
-+
-+static void hso_init_termios(struct ktermios *termios)
-+{
-+ /*
-+ * The default requirements for this device are:
-+ */
-+ termios->c_iflag &=
-+ ~(IGNBRK /* disable ignore break */
-+ | BRKINT /* disable break causes interrupt */
-+ | PARMRK /* disable mark parity errors */
-+ | ISTRIP /* disable clear high bit of input characters */
-+ | INLCR /* disable translate NL to CR */
-+ | IGNCR /* disable ignore CR */
-+ | ICRNL /* disable translate CR to NL */
-+ | IXON); /* disable enable XON/XOFF flow control */
-+
-+ /* disable postprocess output characters */
-+ termios->c_oflag &= ~OPOST;
-+
-+ termios->c_lflag &=
-+ ~(ECHO /* disable echo input characters */
-+ | ECHONL /* disable echo new line */
-+ | ICANON /* disable erase, kill, werase, and rprnt
-+ special characters */
-+ | ISIG /* disable interrupt, quit, and suspend special
-+ characters */
-+ | IEXTEN); /* disable non-POSIX special characters */
-+
-+ termios->c_cflag &=
-+ ~(CSIZE /* no size */
-+ | PARENB /* disable parity bit */
-+ | CBAUD /* clear current baud rate */
-+ | CBAUDEX); /* clear current buad rate */
-+
-+ termios->c_cflag |= CS8; /* character size 8 bits */
-+
-+ /* baud rate 115200 */
-+ tty_termios_encode_baud_rate(termios, 115200, 115200);
-+}
-+
-+static void _hso_serial_set_termios(struct tty_struct *tty,
-+ struct ktermios *old)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+
-+ if (!serial) {
-+ printk(KERN_ERR "%s: no tty structures", __func__);
-+ return;
-+ }
-+
-+ D4("port %d", serial->minor);
-+
-+ /*
-+ * Fix up unsupported bits
-+ */
-+ tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
-+
-+ tty->termios.c_cflag &=
-+ ~(CSIZE /* no size */
-+ | PARENB /* disable parity bit */
-+ | CBAUD /* clear current baud rate */
-+ | CBAUDEX); /* clear current buad rate */
-+
-+ tty->termios.c_cflag |= CS8; /* character size 8 bits */
-+
-+ /* baud rate 115200 */
-+ tty_encode_baud_rate(tty, 115200, 115200);
-+}
-+
-+static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
-+{
-+ int result;
-+ /* We are done with this URB, resubmit it. Prep the USB to wait for
-+ * another frame */
-+ usb_fill_bulk_urb(urb, serial->parent->usb,
-+ usb_rcvbulkpipe(serial->parent->usb,
-+ serial->in_endp->
-+ bEndpointAddress & 0x7F),
-+ urb->transfer_buffer, serial->rx_data_length,
-+ hso_std_serial_read_bulk_callback, serial);
-+ /* Give this to the USB subsystem so it can tell us when more data
-+ * arrives. */
-+ result = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (result) {
-+ dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n",
-+ __func__, result);
-+ }
-+}
-+
-+
-+
-+
-+static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial)
-+{
-+ int count;
-+ struct urb *curr_urb;
-+
-+ while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) {
-+ curr_urb = serial->rx_urb[serial->curr_rx_urb_idx];
-+ count = put_rxbuf_data(curr_urb, serial);
-+ if (count == -1)
-+ return;
-+ if (count == 0) {
-+ serial->curr_rx_urb_idx++;
-+ if (serial->curr_rx_urb_idx >= serial->num_rx_urbs)
-+ serial->curr_rx_urb_idx = 0;
-+ hso_resubmit_rx_bulk_urb(serial, curr_urb);
-+ }
-+ }
-+}
-+
-+static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
-+{
-+ int count = 0;
-+ struct urb *urb;
-+
-+ urb = serial->rx_urb[0];
-+ if (atomic_read(&serial->port.count) > 0) {
-+ count = put_rxbuf_data(urb, serial);
-+ if (count == -1)
-+ return;
-+ }
-+ /* Re issue a read as long as we receive data. */
-+
-+ if (count == 0 && ((urb->actual_length != 0) ||
-+ (serial->rx_state == RX_PENDING))) {
-+ serial->rx_state = RX_SENT;
-+ hso_mux_serial_read(serial);
-+ } else
-+ serial->rx_state = RX_IDLE;
-+}
-+
-+
-+/* read callback for Diag and CS port */
-+static void hso_std_serial_read_bulk_callback(struct urb *urb)
-+{
-+ struct hso_serial *serial = urb->context;
-+ int status = urb->status;
-+
-+ D4("\n--- Got serial_read_bulk callback %02x ---", status);
-+
-+ /* sanity check */
-+ if (!serial) {
-+ D1("serial == NULL");
-+ return;
-+ }
-+ if (status) {
-+ handle_usb_error(status, __func__, serial->parent);
-+ return;
-+ }
-+
-+ D1("Actual length = %d\n", urb->actual_length);
-+ DUMP1(urb->transfer_buffer, urb->actual_length);
-+
-+ /* Anyone listening? */
-+ if (atomic_read(&serial->port.count) == 0)
-+ return;
-+
-+ if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
-+ fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
-+ /* Valid data, handle RX data */
-+ spin_lock(&serial->serial_lock);
-+ serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
-+ put_rxbuf_data_and_resubmit_bulk_urb(serial);
-+ spin_unlock(&serial->serial_lock);
-+}
-+
-+/*
-+ * This needs to be a tasklet otherwise we will
-+ * end up recursively calling this function.
-+ */
-+static void hso_unthrottle_tasklet(struct hso_serial *serial)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ if ((serial->parent->port_spec & HSO_INTF_MUX))
-+ put_rxbuf_data_and_resubmit_ctrl_urb(serial);
-+ else
-+ put_rxbuf_data_and_resubmit_bulk_urb(serial);
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+}
-+
-+static void hso_unthrottle(struct tty_struct *tty)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+
-+ tasklet_hi_schedule(&serial->unthrottle_tasklet);
-+}
-+
-+/* open the requested serial port */
-+static int hso_serial_open(struct tty_struct *tty, struct file *filp)
-+{
-+ struct hso_serial *serial = get_serial_by_index(tty->index);
-+ int result;
-+
-+ /* sanity check */
-+ if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
-+ WARN_ON(1);
-+ tty->driver_data = NULL;
-+ D1("Failed to open port");
-+ return -ENODEV;
-+ }
-+
-+ mutex_lock(&serial->parent->mutex);
-+ result = usb_autopm_get_interface(serial->parent->interface);
-+ if (result < 0)
-+ goto err_out;
-+
-+ D1("Opening %d", serial->minor);
-+
-+ /* setup */
-+ tty->driver_data = serial;
-+ tty_port_tty_set(&serial->port, tty);
-+
-+ /* check for port already opened, if not set the termios */
-+ if (atomic_inc_return(&serial->port.count) == 1) {
-+ serial->rx_state = RX_IDLE;
-+ /* Force default termio settings */
-+ _hso_serial_set_termios(tty, NULL);
-+ tasklet_init(&serial->unthrottle_tasklet,
-+ (void (*)(unsigned long))hso_unthrottle_tasklet,
-+ (unsigned long)serial);
-+ result = hso_start_serial_device(serial->parent, GFP_KERNEL);
-+ if (result) {
-+ hso_stop_serial_device(serial->parent);
-+ atomic_dec(&serial->port.count);
-+ } else {
-+ kref_get(&serial->parent->ref);
-+ }
-+ } else {
-+ D1("Port was already open");
-+ }
-+
-+ usb_autopm_put_interface(serial->parent->interface);
-+
-+ /* done */
-+ if (result)
-+ hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0);
-+err_out:
-+ mutex_unlock(&serial->parent->mutex);
-+ return result;
-+}
-+
-+/* close the requested serial port */
-+static void hso_serial_close(struct tty_struct *tty, struct file *filp)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ u8 usb_gone;
-+
-+ D1("Closing serial port");
-+
-+ /* Open failed, no close cleanup required */
-+ if (serial == NULL)
-+ return;
-+
-+ mutex_lock(&serial->parent->mutex);
-+ usb_gone = serial->parent->usb_gone;
-+
-+ if (!usb_gone)
-+ usb_autopm_get_interface(serial->parent->interface);
-+
-+ /* reset the rts and dtr */
-+ /* do the actual close */
-+ atomic_dec(&serial->port.count);
-+
-+ if (atomic_read(&serial->port.count) <= 0) {
-+ atomic_set(&serial->port.count, 0);
-+ tty_port_tty_set(&serial->port, NULL);
-+ if (!usb_gone)
-+ hso_stop_serial_device(serial->parent);
-+ tasklet_kill(&serial->unthrottle_tasklet);
-+ }
-+
-+ if (!usb_gone)
-+ usb_autopm_put_interface(serial->parent->interface);
-+
-+ mutex_unlock(&serial->parent->mutex);
-+}
-+
-+/* close the requested serial port */
-+static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
-+ int count)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ int space, tx_bytes;
-+ unsigned long flags;
-+
-+ /* sanity check */
-+ if (serial == NULL) {
-+ printk(KERN_ERR "%s: serial is NULL\n", __func__);
-+ return -ENODEV;
-+ }
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+
-+ space = serial->tx_data_length - serial->tx_buffer_count;
-+ tx_bytes = (count < space) ? count : space;
-+
-+ if (!tx_bytes)
-+ goto out;
-+
-+ memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes);
-+ serial->tx_buffer_count += tx_bytes;
-+
-+out:
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+
-+ hso_kick_transmit(serial);
-+ /* done */
-+ return tx_bytes;
-+}
-+
-+/* how much room is there for writing */
-+static int hso_serial_write_room(struct tty_struct *tty)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ int room;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ room = serial->tx_data_length - serial->tx_buffer_count;
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+
-+ /* return free room */
-+ return room;
-+}
-+
-+static void hso_serial_cleanup(struct tty_struct *tty)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+
-+ if (!serial)
-+ return;
-+
-+ kref_put(&serial->parent->ref, hso_serial_ref_free);
-+}
-+
-+/* setup the term */
-+static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ unsigned long flags;
-+
-+ if (old)
-+ D5("Termios called with: cflags new[%d] - old[%d]",
-+ tty->termios.c_cflag, old->c_cflag);
-+
-+ /* the actual setup */
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ if (atomic_read(&serial->port.count))
-+ _hso_serial_set_termios(tty, old);
-+ else
-+ tty->termios = *old;
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+
-+ /* done */
-+}
-+
-+/* how many characters in the buffer */
-+static int hso_serial_chars_in_buffer(struct tty_struct *tty)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ int chars;
-+ unsigned long flags;
-+
-+ /* sanity check */
-+ if (serial == NULL)
-+ return 0;
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ chars = serial->tx_buffer_count;
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+
-+ return chars;
-+}
-+static int tiocmget_submit_urb(struct hso_serial *serial,
-+ struct hso_tiocmget *tiocmget,
-+ struct usb_device *usb)
-+{
-+ int result;
-+
-+ if (serial->parent->usb_gone)
-+ return -ENODEV;
-+ usb_fill_int_urb(tiocmget->urb, usb,
-+ usb_rcvintpipe(usb,
-+ tiocmget->endp->
-+ bEndpointAddress & 0x7F),
-+ &tiocmget->serial_state_notification,
-+ sizeof(struct hso_serial_state_notification),
-+ tiocmget_intr_callback, serial,
-+ tiocmget->endp->bInterval);
-+ result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
-+ if (result) {
-+ dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
-+ result);
-+ }
-+ return result;
-+
-+}
-+
-+static void tiocmget_intr_callback(struct urb *urb)
-+{
-+ struct hso_serial *serial = urb->context;
-+ struct hso_tiocmget *tiocmget;
-+ int status = urb->status;
-+ u16 UART_state_bitmap, prev_UART_state_bitmap;
-+ struct uart_icount *icount;
-+ struct hso_serial_state_notification *serial_state_notification;
-+ struct usb_device *usb;
-+ struct usb_interface *interface;
-+ int if_num;
-+
-+ /* Sanity checks */
-+ if (!serial)
-+ return;
-+ if (status) {
-+ handle_usb_error(status, __func__, serial->parent);
-+ return;
-+ }
-+
-+ /* tiocmget is only supported on HSO_PORT_MODEM */
-+ tiocmget = serial->tiocmget;
-+ if (!tiocmget)
-+ return;
-+ BUG_ON((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM);
-+
-+ usb = serial->parent->usb;
-+ interface = serial->parent->interface;
-+
-+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
-+
-+ /* wIndex should be the USB interface number of the port to which the
-+ * notification applies, which should always be the Modem port.
-+ */
-+ serial_state_notification = &tiocmget->serial_state_notification;
-+ if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
-+ serial_state_notification->bNotification != B_NOTIFICATION ||
-+ le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
-+ le16_to_cpu(serial_state_notification->wIndex) != if_num ||
-+ le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
-+ dev_warn(&usb->dev,
-+ "hso received invalid serial state notification\n");
-+ DUMP(serial_state_notification,
-+ sizeof(struct hso_serial_state_notification));
-+ } else {
-+
-+ UART_state_bitmap = le16_to_cpu(serial_state_notification->
-+ UART_state_bitmap);
-+ prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
-+ icount = &tiocmget->icount;
-+ spin_lock(&serial->serial_lock);
-+ if ((UART_state_bitmap & B_OVERRUN) !=
-+ (prev_UART_state_bitmap & B_OVERRUN))
-+ icount->parity++;
-+ if ((UART_state_bitmap & B_PARITY) !=
-+ (prev_UART_state_bitmap & B_PARITY))
-+ icount->parity++;
-+ if ((UART_state_bitmap & B_FRAMING) !=
-+ (prev_UART_state_bitmap & B_FRAMING))
-+ icount->frame++;
-+ if ((UART_state_bitmap & B_RING_SIGNAL) &&
-+ !(prev_UART_state_bitmap & B_RING_SIGNAL))
-+ icount->rng++;
-+ if ((UART_state_bitmap & B_BREAK) !=
-+ (prev_UART_state_bitmap & B_BREAK))
-+ icount->brk++;
-+ if ((UART_state_bitmap & B_TX_CARRIER) !=
-+ (prev_UART_state_bitmap & B_TX_CARRIER))
-+ icount->dsr++;
-+ if ((UART_state_bitmap & B_RX_CARRIER) !=
-+ (prev_UART_state_bitmap & B_RX_CARRIER))
-+ icount->dcd++;
-+ tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
-+ spin_unlock(&serial->serial_lock);
-+ tiocmget->intr_completed = 1;
-+ wake_up_interruptible(&tiocmget->waitq);
-+ }
-+ memset(serial_state_notification, 0,
-+ sizeof(struct hso_serial_state_notification));
-+ tiocmget_submit_urb(serial,
-+ tiocmget,
-+ serial->parent->usb);
-+}
-+
-+/*
-+ * next few functions largely stolen from drivers/serial/serial_core.c
-+ */
-+/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
-+ * - mask passed in arg for lines of interest
-+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
-+ * Caller should use TIOCGICOUNT to see which one it was
-+ */
-+static int
-+hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
-+{
-+ DECLARE_WAITQUEUE(wait, current);
-+ struct uart_icount cprev, cnow;
-+ struct hso_tiocmget *tiocmget;
-+ int ret;
-+
-+ tiocmget = serial->tiocmget;
-+ if (!tiocmget)
-+ return -ENOENT;
-+ /*
-+ * note the counters on entry
-+ */
-+ spin_lock_irq(&serial->serial_lock);
-+ memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
-+ spin_unlock_irq(&serial->serial_lock);
-+ add_wait_queue(&tiocmget->waitq, &wait);
-+ for (;;) {
-+ spin_lock_irq(&serial->serial_lock);
-+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
-+ spin_unlock_irq(&serial->serial_lock);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
-+ ret = 0;
-+ break;
-+ }
-+ schedule();
-+ /* see if a signal did it */
-+ if (signal_pending(current)) {
-+ ret = -ERESTARTSYS;
-+ break;
-+ }
-+ cprev = cnow;
-+ }
-+ __set_current_state(TASK_RUNNING);
-+ remove_wait_queue(&tiocmget->waitq, &wait);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-+ * Return: write counters to the user passed counter struct
-+ * NB: both 1->0 and 0->1 transitions are counted except for
-+ * RI where only 0->1 is counted.
-+ */
-+static int hso_get_count(struct tty_struct *tty,
-+ struct serial_icounter_struct *icount)
-+{
-+ struct uart_icount cnow;
-+ struct hso_serial *serial = tty->driver_data;
-+ struct hso_tiocmget *tiocmget = serial->tiocmget;
-+
-+ memset(icount, 0, sizeof(struct serial_icounter_struct));
-+
-+ if (!tiocmget)
-+ return -ENOENT;
-+ spin_lock_irq(&serial->serial_lock);
-+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
-+ spin_unlock_irq(&serial->serial_lock);
-+
-+ icount->cts = cnow.cts;
-+ icount->dsr = cnow.dsr;
-+ icount->rng = cnow.rng;
-+ icount->dcd = cnow.dcd;
-+ icount->rx = cnow.rx;
-+ icount->tx = cnow.tx;
-+ icount->frame = cnow.frame;
-+ icount->overrun = cnow.overrun;
-+ icount->parity = cnow.parity;
-+ icount->brk = cnow.brk;
-+ icount->buf_overrun = cnow.buf_overrun;
-+
-+ return 0;
-+}
-+
-+
-+static int hso_serial_tiocmget(struct tty_struct *tty)
-+{
-+ int retval;
-+ struct hso_serial *serial = tty->driver_data;
-+ struct hso_tiocmget *tiocmget;
-+ u16 UART_state_bitmap;
-+
-+ /* sanity check */
-+ if (!serial) {
-+ D1("no tty structures");
-+ return -EINVAL;
-+ }
-+ spin_lock_irq(&serial->serial_lock);
-+ retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
-+ ((serial->dtr_state) ? TIOCM_DTR : 0);
-+ tiocmget = serial->tiocmget;
-+ if (tiocmget) {
-+
-+ UART_state_bitmap = le16_to_cpu(
-+ tiocmget->prev_UART_state_bitmap);
-+ if (UART_state_bitmap & B_RING_SIGNAL)
-+ retval |= TIOCM_RNG;
-+ if (UART_state_bitmap & B_RX_CARRIER)
-+ retval |= TIOCM_CD;
-+ if (UART_state_bitmap & B_TX_CARRIER)
-+ retval |= TIOCM_DSR;
-+ }
-+ spin_unlock_irq(&serial->serial_lock);
-+ return retval;
-+}
-+
-+static int hso_serial_tiocmset(struct tty_struct *tty,
-+ unsigned int set, unsigned int clear)
-+{
-+ int val = 0;
-+ unsigned long flags;
-+ int if_num;
-+ struct hso_serial *serial = tty->driver_data;
-+ struct usb_interface *interface;
-+
-+ /* sanity check */
-+ if (!serial) {
-+ D1("no tty structures");
-+ return -EINVAL;
-+ }
-+
-+ if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM)
-+ return -EINVAL;
-+
-+ interface = serial->parent->interface;
-+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ if (set & TIOCM_RTS)
-+ serial->rts_state = 1;
-+ if (set & TIOCM_DTR)
-+ serial->dtr_state = 1;
-+
-+ if (clear & TIOCM_RTS)
-+ serial->rts_state = 0;
-+ if (clear & TIOCM_DTR)
-+ serial->dtr_state = 0;
-+
-+ if (serial->dtr_state)
-+ val |= 0x01;
-+ if (serial->rts_state)
-+ val |= 0x02;
-+
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+
-+ return usb_control_msg(serial->parent->usb,
-+ usb_rcvctrlpipe(serial->parent->usb, 0), 0x22,
-+ 0x21, val, if_num, NULL, 0,
-+ USB_CTRL_SET_TIMEOUT);
-+}
-+
-+static int hso_serial_ioctl(struct tty_struct *tty,
-+ unsigned int cmd, unsigned long arg)
-+{
-+ struct hso_serial *serial = tty->driver_data;
-+ int ret = 0;
-+ D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
-+
-+ if (!serial)
-+ return -ENODEV;
-+ switch (cmd) {
-+ case TIOCMIWAIT:
-+ ret = hso_wait_modem_status(serial, arg);
-+ break;
-+ default:
-+ ret = -ENOIOCTLCMD;
-+ break;
-+ }
-+ return ret;
-+}
-+
-+
-+/* starts a transmit */
-+static void hso_kick_transmit(struct hso_serial *serial)
-+{
-+ u8 *temp;
-+ unsigned long flags;
-+ int res;
-+
-+ spin_lock_irqsave(&serial->serial_lock, flags);
-+ if (!serial->tx_buffer_count)
-+ goto out;
-+
-+ if (serial->tx_urb_used)
-+ goto out;
-+
-+ /* Wakeup USB interface if necessary */
-+ if (hso_get_activity(serial->parent) == -EAGAIN)
-+ goto out;
-+
-+ /* Switch pointers around to avoid memcpy */
-+ temp = serial->tx_buffer;
-+ serial->tx_buffer = serial->tx_data;
-+ serial->tx_data = temp;
-+ serial->tx_data_count = serial->tx_buffer_count;
-+ serial->tx_buffer_count = 0;
-+
-+ /* If temp is set, it means we switched buffers */
-+ if (temp && serial->write_data) {
-+ res = serial->write_data(serial);
-+ if (res >= 0)
-+ serial->tx_urb_used = 1;
-+ }
-+out:
-+ spin_unlock_irqrestore(&serial->serial_lock, flags);
-+}
-+
-+/* make a request (for reading and writing data to muxed serial port) */
-+static int mux_device_request(struct hso_serial *serial, u8 type, u16 port,
-+ struct urb *ctrl_urb,
-+ struct usb_ctrlrequest *ctrl_req,
-+ u8 *ctrl_urb_data, u32 size)
-+{
-+ int result;
-+ int pipe;
-+
-+ /* Sanity check */
-+ if (!serial || !ctrl_urb || !ctrl_req) {
-+ printk(KERN_ERR "%s: Wrong arguments\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ /* initialize */
-+ ctrl_req->wValue = 0;
-+ ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port));
-+ ctrl_req->wLength = cpu_to_le16(size);
-+
-+ if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) {
-+ /* Reading command */
-+ ctrl_req->bRequestType = USB_DIR_IN |
-+ USB_TYPE_OPTION_VENDOR |
-+ USB_RECIP_INTERFACE;
-+ ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
-+ pipe = usb_rcvctrlpipe(serial->parent->usb, 0);
-+ } else {
-+ /* Writing command */
-+ ctrl_req->bRequestType = USB_DIR_OUT |
-+ USB_TYPE_OPTION_VENDOR |
-+ USB_RECIP_INTERFACE;
-+ ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
-+ pipe = usb_sndctrlpipe(serial->parent->usb, 0);
-+ }
-+ /* syslog */
-+ D2("%s command (%02x) len: %d, port: %d",
-+ type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write",
-+ ctrl_req->bRequestType, ctrl_req->wLength, port);
-+
-+ /* Load ctrl urb */
-+ ctrl_urb->transfer_flags = 0;
-+ usb_fill_control_urb(ctrl_urb,
-+ serial->parent->usb,
-+ pipe,
-+ (u8 *) ctrl_req,
-+ ctrl_urb_data, size, ctrl_callback, serial);
-+ /* Send it on merry way */
-+ result = usb_submit_urb(ctrl_urb, GFP_ATOMIC);
-+ if (result) {
-+ dev_err(&ctrl_urb->dev->dev,
-+ "%s failed submit ctrl_urb %d type %d\n", __func__,
-+ result, type);
-+ return result;
-+ }
-+
-+ /* done */
-+ return size;
-+}
-+
-+/* called by intr_callback when read occurs */
-+static int hso_mux_serial_read(struct hso_serial *serial)
-+{
-+ if (!serial)
-+ return -EINVAL;
-+
-+ /* clean data */
-+ memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE);
-+ /* make the request */
-+
-+ if (serial->num_rx_urbs != 1) {
-+ dev_err(&serial->parent->interface->dev,
-+ "ERROR: mux'd reads with multiple buffers "
-+ "not possible\n");
-+ return 0;
-+ }
-+ return mux_device_request(serial,
-+ USB_CDC_GET_ENCAPSULATED_RESPONSE,
-+ serial->parent->port_spec & HSO_PORT_MASK,
-+ serial->rx_urb[0],
-+ &serial->ctrl_req_rx,
-+ serial->rx_data[0], serial->rx_data_length);
-+}
-+
-+/* used for muxed serial port callback (muxed serial read) */
-+static void intr_callback(struct urb *urb)
-+{
-+ struct hso_shared_int *shared_int = urb->context;
-+ struct hso_serial *serial;
-+ unsigned char *port_req;
-+ int status = urb->status;
-+ int i;
-+
-+ usb_mark_last_busy(urb->dev);
-+
-+ /* sanity check */
-+ if (!shared_int)
-+ return;
-+
-+ /* status check */
-+ if (status) {
-+ handle_usb_error(status, __func__, NULL);
-+ return;
-+ }
-+ D4("\n--- Got intr callback 0x%02X ---", status);
-+
-+ /* what request? */
-+ port_req = urb->transfer_buffer;
-+ D4(" port_req = 0x%.2X\n", *port_req);
-+ /* loop over all muxed ports to find the one sending this */
-+ for (i = 0; i < 8; i++) {
-+ /* max 8 channels on MUX */
-+ if (*port_req & (1 << i)) {
-+ serial = get_serial_by_shared_int_and_type(shared_int,
-+ (1 << i));
-+ if (serial != NULL) {
-+ D1("Pending read interrupt on port %d\n", i);
-+ spin_lock(&serial->serial_lock);
-+ if (serial->rx_state == RX_IDLE &&
-+ atomic_read(&serial->port.count) > 0) {
-+ /* Setup and send a ctrl req read on
-+ * port i */
-+ if (!serial->rx_urb_filled[0]) {
-+ serial->rx_state = RX_SENT;
-+ hso_mux_serial_read(serial);
-+ } else
-+ serial->rx_state = RX_PENDING;
-+ } else {
-+ D1("Already a read pending on "
-+ "port %d or port not open\n", i);
-+ }
-+ spin_unlock(&serial->serial_lock);
-+ }
-+ }
-+ }
-+ /* Resubmit interrupt urb */
-+ hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC);
-+}
-+
-+/* called for writing to muxed serial port */
-+static int hso_mux_serial_write_data(struct hso_serial *serial)
-+{
-+ if (NULL == serial)
-+ return -EINVAL;
-+
-+ return mux_device_request(serial,
-+ USB_CDC_SEND_ENCAPSULATED_COMMAND,
-+ serial->parent->port_spec & HSO_PORT_MASK,
-+ serial->tx_urb,
-+ &serial->ctrl_req_tx,
-+ serial->tx_data, serial->tx_data_count);
-+}
-+
-+/* write callback for Diag and CS port */
-+static void hso_std_serial_write_bulk_callback(struct urb *urb)
-+{
-+ struct hso_serial *serial = urb->context;
-+ int status = urb->status;
-+
-+ /* sanity check */
-+ if (!serial) {
-+ D1("serial == NULL");
-+ return;
-+ }
-+
-+ spin_lock(&serial->serial_lock);
-+ serial->tx_urb_used = 0;
-+ spin_unlock(&serial->serial_lock);
-+ if (status) {
-+ handle_usb_error(status, __func__, serial->parent);
-+ return;
-+ }
-+ hso_put_activity(serial->parent);
-+ tty_port_tty_wakeup(&serial->port);
-+ hso_kick_transmit(serial);
-+
-+ D1(" ");
-+}
-+
-+/* called for writing diag or CS serial port */
-+static int hso_std_serial_write_data(struct hso_serial *serial)
-+{
-+ int count = serial->tx_data_count;
-+ int result;
-+
-+ usb_fill_bulk_urb(serial->tx_urb,
-+ serial->parent->usb,
-+ usb_sndbulkpipe(serial->parent->usb,
-+ serial->out_endp->
-+ bEndpointAddress & 0x7F),
-+ serial->tx_data, serial->tx_data_count,
-+ hso_std_serial_write_bulk_callback, serial);
-+
-+ result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC);
-+ if (result) {
-+ dev_warn(&serial->parent->usb->dev,
-+ "Failed to submit urb - res %d\n", result);
-+ return result;
-+ }
-+
-+ return count;
-+}
-+
-+/* callback after read or write on muxed serial port */
-+static void ctrl_callback(struct urb *urb)
-+{
-+ struct hso_serial *serial = urb->context;
-+ struct usb_ctrlrequest *req;
-+ int status = urb->status;
-+
-+ /* sanity check */
-+ if (!serial)
-+ return;
-+
-+ spin_lock(&serial->serial_lock);
-+ serial->tx_urb_used = 0;
-+ spin_unlock(&serial->serial_lock);
-+ if (status) {
-+ handle_usb_error(status, __func__, serial->parent);
-+ return;
-+ }
-+
-+ /* what request? */
-+ req = (struct usb_ctrlrequest *)(urb->setup_packet);
-+ D4("\n--- Got muxed ctrl callback 0x%02X ---", status);
-+ D4("Actual length of urb = %d\n", urb->actual_length);
-+ DUMP1(urb->transfer_buffer, urb->actual_length);
-+
-+ if (req->bRequestType ==
-+ (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {
-+ /* response to a read command */
-+ serial->rx_urb_filled[0] = 1;
-+ spin_lock(&serial->serial_lock);
-+ put_rxbuf_data_and_resubmit_ctrl_urb(serial);
-+ spin_unlock(&serial->serial_lock);
-+ } else {
-+ hso_put_activity(serial->parent);
-+ tty_port_tty_wakeup(&serial->port);
-+ /* response to a write command */
-+ hso_kick_transmit(serial);
-+ }
-+}
-+
-+/* handle RX data for serial port */
-+static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
-+{
-+ struct tty_struct *tty;
-+ int count;
-+
-+ /* Sanity check */
-+ if (urb == NULL || serial == NULL) {
-+ D1("serial = NULL");
-+ return -2;
-+ }
-+
-+ tty = tty_port_tty_get(&serial->port);
-+
-+ if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
-+ tty_kref_put(tty);
-+ return -1;
-+ }
-+
-+ /* Push data to tty */
-+ D1("data to push to tty");
-+ count = tty_buffer_request_room(&serial->port, urb->actual_length);
-+ if (count >= urb->actual_length) {
-+ tty_insert_flip_string(&serial->port, urb->transfer_buffer,
-+ urb->actual_length);
-+ tty_flip_buffer_push(&serial->port);
-+ } else {
-+ dev_warn(&serial->parent->usb->dev,
-+ "dropping data, %d bytes lost\n", urb->actual_length);
-+ }
-+
-+ tty_kref_put(tty);
-+
-+ serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
-+
-+ return 0;
-+}
-+
-+
-+/* Base driver functions */
-+
-+static void hso_log_port(struct hso_device *hso_dev)
-+{
-+ char *port_type;
-+ char port_dev[20];
-+
-+ switch (hso_dev->port_spec & HSO_PORT_MASK) {
-+ case HSO_PORT_CONTROL:
-+ port_type = "Control";
-+ break;
-+ case HSO_PORT_APP:
-+ port_type = "Application";
-+ break;
-+ case HSO_PORT_GPS:
-+ port_type = "GPS";
-+ break;
-+ case HSO_PORT_GPS_CONTROL:
-+ port_type = "GPS control";
-+ break;
-+ case HSO_PORT_APP2:
-+ port_type = "Application2";
-+ break;
-+ case HSO_PORT_PCSC:
-+ port_type = "PCSC";
-+ break;
-+ case HSO_PORT_DIAG:
-+ port_type = "Diagnostic";
-+ break;
-+ case HSO_PORT_DIAG2:
-+ port_type = "Diagnostic2";
-+ break;
-+ case HSO_PORT_MODEM:
-+ port_type = "Modem";
-+ break;
-+ case HSO_PORT_NETWORK:
-+ port_type = "Network";
-+ break;
-+ default:
-+ port_type = "Unknown";
-+ break;
-+ }
-+ if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
-+ sprintf(port_dev, "%s", dev2net(hso_dev)->net->name);
-+ } else
-+ sprintf(port_dev, "/dev/%s%d", tty_filename,
-+ dev2ser(hso_dev)->minor);
-+
-+ dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n",
-+ port_type, port_dev);
-+}
-+
-+static int hso_start_net_device(struct hso_device *hso_dev)
-+{
-+ int i, result = 0;
-+ struct hso_net *hso_net = dev2net(hso_dev);
-+
-+ if (!hso_net)
-+ return -ENODEV;
-+
-+ /* send URBs for all read buffers */
-+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
-+
-+ /* Prep a receive URB */
-+ usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i],
-+ hso_dev->usb,
-+ usb_rcvbulkpipe(hso_dev->usb,
-+ hso_net->in_endp->
-+ bEndpointAddress & 0x7F),
-+ hso_net->mux_bulk_rx_buf_pool[i],
-+ MUX_BULK_RX_BUF_SIZE, read_bulk_callback,
-+ hso_net);
-+
-+ /* Put it out there so the device can send us stuff */
-+ result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i],
-+ GFP_NOIO);
-+ if (result)
-+ dev_warn(&hso_dev->usb->dev,
-+ "%s failed mux_bulk_rx_urb[%d] %d\n", __func__,
-+ i, result);
-+ }
-+
-+ return result;
-+}
-+
-+static int hso_stop_net_device(struct hso_device *hso_dev)
-+{
-+ int i;
-+ struct hso_net *hso_net = dev2net(hso_dev);
-+
-+ if (!hso_net)
-+ return -ENODEV;
-+
-+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
-+ if (hso_net->mux_bulk_rx_urb_pool[i])
-+ usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]);
-+
-+ }
-+ if (hso_net->mux_bulk_tx_urb)
-+ usb_kill_urb(hso_net->mux_bulk_tx_urb);
-+
-+ return 0;
-+}
-+
-+static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
-+{
-+ int i, result = 0;
-+ struct hso_serial *serial = dev2ser(hso_dev);
-+
-+ if (!serial)
-+ return -ENODEV;
-+
-+ /* If it is not the MUX port fill in and submit a bulk urb (already
-+ * allocated in hso_serial_start) */
-+ if (!(serial->parent->port_spec & HSO_INTF_MUX)) {
-+ for (i = 0; i < serial->num_rx_urbs; i++) {
-+ usb_fill_bulk_urb(serial->rx_urb[i],
-+ serial->parent->usb,
-+ usb_rcvbulkpipe(serial->parent->usb,
-+ serial->in_endp->
-+ bEndpointAddress &
-+ 0x7F),
-+ serial->rx_data[i],
-+ serial->rx_data_length,
-+ hso_std_serial_read_bulk_callback,
-+ serial);
-+ result = usb_submit_urb(serial->rx_urb[i], flags);
-+ if (result) {
-+ dev_warn(&serial->parent->usb->dev,
-+ "Failed to submit urb - res %d\n",
-+ result);
-+ break;
-+ }
-+ }
-+ } else {
-+ mutex_lock(&serial->shared_int->shared_int_lock);
-+ if (!serial->shared_int->use_count) {
-+ result =
-+ hso_mux_submit_intr_urb(serial->shared_int,
-+ hso_dev->usb, flags);
-+ }
-+ serial->shared_int->use_count++;
-+ mutex_unlock(&serial->shared_int->shared_int_lock);
-+ }
-+ if (serial->tiocmget)
-+ tiocmget_submit_urb(serial,
-+ serial->tiocmget,
-+ serial->parent->usb);
-+ return result;
-+}
-+
-+static int hso_stop_serial_device(struct hso_device *hso_dev)
-+{
-+ int i;
-+ struct hso_serial *serial = dev2ser(hso_dev);
-+ struct hso_tiocmget *tiocmget;
-+
-+ if (!serial)
-+ return -ENODEV;
-+
-+ for (i = 0; i < serial->num_rx_urbs; i++) {
-+ if (serial->rx_urb[i]) {
-+ usb_kill_urb(serial->rx_urb[i]);
-+ serial->rx_urb_filled[i] = 0;
-+ }
-+ }
-+ serial->curr_rx_urb_idx = 0;
-+
-+ if (serial->tx_urb)
-+ usb_kill_urb(serial->tx_urb);
-+
-+ if (serial->shared_int) {
-+ mutex_lock(&serial->shared_int->shared_int_lock);
-+ if (serial->shared_int->use_count &&
-+ (--serial->shared_int->use_count == 0)) {
-+ struct urb *urb;
-+
-+ urb = serial->shared_int->shared_intr_urb;
-+ if (urb)
-+ usb_kill_urb(urb);
-+ }
-+ mutex_unlock(&serial->shared_int->shared_int_lock);
-+ }
-+ tiocmget = serial->tiocmget;
-+ if (tiocmget) {
-+ wake_up_interruptible(&tiocmget->waitq);
-+ usb_kill_urb(tiocmget->urb);
-+ }
-+
-+ return 0;
-+}
-+
-+static void hso_serial_tty_unregister(struct hso_serial *serial)
-+{
-+ tty_unregister_device(tty_drv, serial->minor);
-+}
-+
-+static void hso_serial_common_free(struct hso_serial *serial)
-+{
-+ int i;
-+
-+ for (i = 0; i < serial->num_rx_urbs; i++) {
-+ /* unlink and free RX URB */
-+ usb_free_urb(serial->rx_urb[i]);
-+ /* free the RX buffer */
-+ kfree(serial->rx_data[i]);
-+ }
-+
-+ /* unlink and free TX URB */
-+ usb_free_urb(serial->tx_urb);
-+ kfree(serial->tx_buffer);
-+ kfree(serial->tx_data);
-+ tty_port_destroy(&serial->port);
-+}
-+
-+static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
-+ int rx_size, int tx_size)
-+{
-+ struct device *dev;
-+ int minor;
-+ int i;
-+
-+ tty_port_init(&serial->port);
-+
-+ minor = get_free_serial_index();
-+ if (minor < 0)
-+ goto exit;
-+
-+ /* register our minor number */
-+ serial->parent->dev = tty_port_register_device_attr(&serial->port,
-+ tty_drv, minor, &serial->parent->interface->dev,
-+ serial->parent, hso_serial_dev_groups);
-+ dev = serial->parent->dev;
-+
-+ /* fill in specific data for later use */
-+ serial->minor = minor;
-+ serial->magic = HSO_SERIAL_MAGIC;
-+ spin_lock_init(&serial->serial_lock);
-+ serial->num_rx_urbs = num_urbs;
-+
-+ /* RX, allocate urb and initialize */
-+
-+ /* prepare our RX buffer */
-+ serial->rx_data_length = rx_size;
-+ for (i = 0; i < serial->num_rx_urbs; i++) {
-+ serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!serial->rx_urb[i]) {
-+ dev_err(dev, "Could not allocate urb?\n");
-+ goto exit;
-+ }
-+ serial->rx_urb[i]->transfer_buffer = NULL;
-+ serial->rx_urb[i]->transfer_buffer_length = 0;
-+ serial->rx_data[i] = kzalloc(serial->rx_data_length,
-+ GFP_KERNEL);
-+ if (!serial->rx_data[i])
-+ goto exit;
-+ }
-+
-+ /* TX, allocate urb and initialize */
-+ serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!serial->tx_urb) {
-+ dev_err(dev, "Could not allocate urb?\n");
-+ goto exit;
-+ }
-+ serial->tx_urb->transfer_buffer = NULL;
-+ serial->tx_urb->transfer_buffer_length = 0;
-+ /* prepare our TX buffer */
-+ serial->tx_data_count = 0;
-+ serial->tx_buffer_count = 0;
-+ serial->tx_data_length = tx_size;
-+ serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL);
-+ if (!serial->tx_data)
-+ goto exit;
-+
-+ serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL);
-+ if (!serial->tx_buffer)
-+ goto exit;
-+
-+ return 0;
-+exit:
-+ hso_serial_tty_unregister(serial);
-+ hso_serial_common_free(serial);
-+ return -1;
-+}
-+
-+/* Creates a general hso device */
-+static struct hso_device *hso_create_device(struct usb_interface *intf,
-+ int port_spec)
-+{
-+ struct hso_device *hso_dev;
-+
-+ hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC);
-+ if (!hso_dev)
-+ return NULL;
-+
-+ hso_dev->port_spec = port_spec;
-+ hso_dev->usb = interface_to_usbdev(intf);
-+ hso_dev->interface = intf;
-+ kref_init(&hso_dev->ref);
-+ mutex_init(&hso_dev->mutex);
-+
-+ INIT_WORK(&hso_dev->async_get_intf, async_get_intf);
-+ INIT_WORK(&hso_dev->async_put_intf, async_put_intf);
-+
-+ return hso_dev;
-+}
-+
-+/* Removes a network device in the network device table */
-+static int remove_net_device(struct hso_device *hso_dev)
-+{
-+ int i;
-+
-+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
-+ if (network_table[i] == hso_dev) {
-+ network_table[i] = NULL;
-+ break;
-+ }
-+ }
-+ if (i == HSO_MAX_NET_DEVICES)
-+ return -1;
-+ return 0;
-+}
-+
-+/* Frees our network device */
-+static void hso_free_net_device(struct hso_device *hso_dev)
-+{
-+ int i;
-+ struct hso_net *hso_net = dev2net(hso_dev);
-+
-+ if (!hso_net)
-+ return;
-+
-+ remove_net_device(hso_net->parent);
-+
-+ if (hso_net->net)
-+ unregister_netdev(hso_net->net);
-+
-+ /* start freeing */
-+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
-+ usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]);
-+ kfree(hso_net->mux_bulk_rx_buf_pool[i]);
-+ hso_net->mux_bulk_rx_buf_pool[i] = NULL;
-+ }
-+ usb_free_urb(hso_net->mux_bulk_tx_urb);
-+ kfree(hso_net->mux_bulk_tx_buf);
-+ hso_net->mux_bulk_tx_buf = NULL;
-+
-+ if (hso_net->net)
-+ free_netdev(hso_net->net);
-+
-+ kfree(hso_dev);
-+}
-+
-+static const struct net_device_ops hso_netdev_ops = {
-+ .ndo_open = hso_net_open,
-+ .ndo_stop = hso_net_close,
-+ .ndo_start_xmit = hso_net_start_xmit,
-+ .ndo_tx_timeout = hso_net_tx_timeout,
-+};
-+
-+/* initialize the network interface */
-+static void hso_net_init(struct net_device *net)
-+{
-+ struct hso_net *hso_net = netdev_priv(net);
-+
-+ D1("sizeof hso_net is %d", (int)sizeof(*hso_net));
-+
-+ /* fill in the other fields */
-+ net->netdev_ops = &hso_netdev_ops;
-+ net->watchdog_timeo = HSO_NET_TX_TIMEOUT;
-+ net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-+ net->type = ARPHRD_NONE;
-+ net->mtu = DEFAULT_MTU - 14;
-+ net->tx_queue_len = 10;
-+ net->ethtool_ops = &ops;
-+
-+ /* and initialize the semaphore */
-+ spin_lock_init(&hso_net->net_lock);
-+}
-+
-+/* Adds a network device in the network device table */
-+static int add_net_device(struct hso_device *hso_dev)
-+{
-+ int i;
-+
-+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
-+ if (network_table[i] == NULL) {
-+ network_table[i] = hso_dev;
-+ break;
-+ }
-+ }
-+ if (i == HSO_MAX_NET_DEVICES)
-+ return -1;
-+ return 0;
-+}
-+
-+static int hso_rfkill_set_block(void *data, bool blocked)
-+{
-+ struct hso_device *hso_dev = data;
-+ int enabled = !blocked;
-+ int rv;
-+
-+ mutex_lock(&hso_dev->mutex);
-+ if (hso_dev->usb_gone)
-+ rv = 0;
-+ else
-+ rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0),
-+ enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0,
-+ USB_CTRL_SET_TIMEOUT);
-+ mutex_unlock(&hso_dev->mutex);
-+ return rv;
-+}
-+
-+static const struct rfkill_ops hso_rfkill_ops = {
-+ .set_block = hso_rfkill_set_block,
-+};
-+
-+/* Creates and sets up everything for rfkill */
-+static void hso_create_rfkill(struct hso_device *hso_dev,
-+ struct usb_interface *interface)
-+{
-+ struct hso_net *hso_net = dev2net(hso_dev);
-+ struct device *dev = &hso_net->net->dev;
-+ static u32 rfkill_counter;
-+
-+ snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d",
-+ rfkill_counter++);
-+
-+ hso_net->rfkill = rfkill_alloc(hso_net->name,
-+ &interface_to_usbdev(interface)->dev,
-+ RFKILL_TYPE_WWAN,
-+ &hso_rfkill_ops, hso_dev);
-+ if (!hso_net->rfkill) {
-+ dev_err(dev, "%s - Out of memory\n", __func__);
-+ return;
-+ }
-+ if (rfkill_register(hso_net->rfkill) < 0) {
-+ rfkill_destroy(hso_net->rfkill);
-+ hso_net->rfkill = NULL;
-+ dev_err(dev, "%s - Failed to register rfkill\n", __func__);
-+ return;
-+ }
-+}
-+
-+static struct device_type hso_type = {
-+ .name = "wwan",
-+};
-+
-+/* Creates our network device */
-+static struct hso_device *hso_create_net_device(struct usb_interface *interface,
-+ int port_spec)
-+{
-+ int result, i;
-+ struct net_device *net;
-+ struct hso_net *hso_net;
-+ struct hso_device *hso_dev;
-+
-+ hso_dev = hso_create_device(interface, port_spec);
-+ if (!hso_dev)
-+ return NULL;
-+
-+ /* allocate our network device, then we can put in our private data */
-+ /* call hso_net_init to do the basic initialization */
-+ net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN,
-+ hso_net_init);
-+ if (!net) {
-+ dev_err(&interface->dev, "Unable to create ethernet device\n");
-+ goto exit;
-+ }
-+
-+ hso_net = netdev_priv(net);
-+
-+ hso_dev->port_data.dev_net = hso_net;
-+ hso_net->net = net;
-+ hso_net->parent = hso_dev;
-+
-+ hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
-+ USB_DIR_IN);
-+ if (!hso_net->in_endp) {
-+ dev_err(&interface->dev, "Can't find BULK IN endpoint\n");
-+ goto exit;
-+ }
-+ hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
-+ USB_DIR_OUT);
-+ if (!hso_net->out_endp) {
-+ dev_err(&interface->dev, "Can't find BULK OUT endpoint\n");
-+ goto exit;
-+ }
-+ SET_NETDEV_DEV(net, &interface->dev);
-+ SET_NETDEV_DEVTYPE(net, &hso_type);
-+
-+ /* registering our net device */
-+ result = register_netdev(net);
-+ if (result) {
-+ dev_err(&interface->dev, "Failed to register device\n");
-+ goto exit;
-+ }
-+
-+ /* start allocating */
-+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
-+ hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!hso_net->mux_bulk_rx_urb_pool[i]) {
-+ dev_err(&interface->dev, "Could not allocate rx urb\n");
-+ goto exit;
-+ }
-+ hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE,
-+ GFP_KERNEL);
-+ if (!hso_net->mux_bulk_rx_buf_pool[i])
-+ goto exit;
-+ }
-+ hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!hso_net->mux_bulk_tx_urb) {
-+ dev_err(&interface->dev, "Could not allocate tx urb\n");
-+ goto exit;
-+ }
-+ hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL);
-+ if (!hso_net->mux_bulk_tx_buf)
-+ goto exit;
-+
-+ add_net_device(hso_dev);
-+
-+ hso_log_port(hso_dev);
-+
-+ hso_create_rfkill(hso_dev, interface);
-+
-+ return hso_dev;
-+exit:
-+ hso_free_net_device(hso_dev);
-+ return NULL;
-+}
-+
-+static void hso_free_tiomget(struct hso_serial *serial)
-+{
-+ struct hso_tiocmget *tiocmget;
-+ if (!serial)
-+ return;
-+ tiocmget = serial->tiocmget;
-+ if (tiocmget) {
-+ usb_free_urb(tiocmget->urb);
-+ tiocmget->urb = NULL;
-+ serial->tiocmget = NULL;
-+ kfree(tiocmget);
-+ }
-+}
-+
-+/* Frees an AT channel ( goes for both mux and non-mux ) */
-+static void hso_free_serial_device(struct hso_device *hso_dev)
-+{
-+ struct hso_serial *serial = dev2ser(hso_dev);
-+
-+ if (!serial)
-+ return;
-+
-+ hso_serial_common_free(serial);
-+
-+ if (serial->shared_int) {
-+ mutex_lock(&serial->shared_int->shared_int_lock);
-+ if (--serial->shared_int->ref_count == 0)
-+ hso_free_shared_int(serial->shared_int);
-+ else
-+ mutex_unlock(&serial->shared_int->shared_int_lock);
-+ }
-+ hso_free_tiomget(serial);
-+ kfree(serial);
-+ kfree(hso_dev);
-+}
-+
-+/* Creates a bulk AT channel */
-+static struct hso_device *hso_create_bulk_serial_device(
-+ struct usb_interface *interface, int port)
-+{
-+ struct hso_device *hso_dev;
-+ struct hso_serial *serial;
-+ int num_urbs;
-+ struct hso_tiocmget *tiocmget;
-+
-+ hso_dev = hso_create_device(interface, port);
-+ if (!hso_dev)
-+ return NULL;
-+
-+ serial = kzalloc(sizeof(*serial), GFP_KERNEL);
-+ if (!serial)
-+ goto exit;
-+
-+ serial->parent = hso_dev;
-+ hso_dev->port_data.dev_serial = serial;
-+
-+ if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
-+ num_urbs = 2;
-+ serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
-+ GFP_KERNEL);
-+ /* it isn't going to break our heart if serial->tiocmget
-+ * allocation fails don't bother checking this.
-+ */
-+ if (serial->tiocmget) {
-+ tiocmget = serial->tiocmget;
-+ tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (tiocmget->urb) {
-+ mutex_init(&tiocmget->mutex);
-+ init_waitqueue_head(&tiocmget->waitq);
-+ tiocmget->endp = hso_get_ep(
-+ interface,
-+ USB_ENDPOINT_XFER_INT,
-+ USB_DIR_IN);
-+ } else
-+ hso_free_tiomget(serial);
-+ }
-+ }
-+ else
-+ num_urbs = 1;
-+
-+ if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE,
-+ BULK_URB_TX_SIZE))
-+ goto exit;
-+
-+ serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
-+ USB_DIR_IN);
-+ if (!serial->in_endp) {
-+ dev_err(&interface->dev, "Failed to find BULK IN ep\n");
-+ goto exit2;
-+ }
-+
-+ if (!
-+ (serial->out_endp =
-+ hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) {
-+ dev_err(&interface->dev, "Failed to find BULK IN ep\n");
-+ goto exit2;
-+ }
-+
-+ serial->write_data = hso_std_serial_write_data;
-+
-+ /* and record this serial */
-+ set_serial_by_index(serial->minor, serial);
-+
-+ /* setup the proc dirs and files if needed */
-+ hso_log_port(hso_dev);
-+
-+ /* done, return it */
-+ return hso_dev;
-+
-+exit2:
-+ hso_serial_tty_unregister(serial);
-+ hso_serial_common_free(serial);
-+exit:
-+ hso_free_tiomget(serial);
-+ kfree(serial);
-+ kfree(hso_dev);
-+ return NULL;
-+}
-+
-+/* Creates a multiplexed AT channel */
-+static
-+struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface,
-+ int port,
-+ struct hso_shared_int *mux)
-+{
-+ struct hso_device *hso_dev;
-+ struct hso_serial *serial;
-+ int port_spec;
-+
-+ port_spec = HSO_INTF_MUX;
-+ port_spec &= ~HSO_PORT_MASK;
-+
-+ port_spec |= hso_mux_to_port(port);
-+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT)
-+ return NULL;
-+
-+ hso_dev = hso_create_device(interface, port_spec);
-+ if (!hso_dev)
-+ return NULL;
-+
-+ serial = kzalloc(sizeof(*serial), GFP_KERNEL);
-+ if (!serial)
-+ goto exit;
-+
-+ hso_dev->port_data.dev_serial = serial;
-+ serial->parent = hso_dev;
-+
-+ if (hso_serial_common_create
-+ (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE))
-+ goto exit;
-+
-+ serial->tx_data_length--;
-+ serial->write_data = hso_mux_serial_write_data;
-+
-+ serial->shared_int = mux;
-+ mutex_lock(&serial->shared_int->shared_int_lock);
-+ serial->shared_int->ref_count++;
-+ mutex_unlock(&serial->shared_int->shared_int_lock);
-+
-+ /* and record this serial */
-+ set_serial_by_index(serial->minor, serial);
-+
-+ /* setup the proc dirs and files if needed */
-+ hso_log_port(hso_dev);
-+
-+ /* done, return it */
-+ return hso_dev;
-+
-+exit:
-+ if (serial) {
-+ tty_unregister_device(tty_drv, serial->minor);
-+ kfree(serial);
-+ }
-+ kfree(hso_dev);
-+ return NULL;
-+
-+}
-+
-+static void hso_free_shared_int(struct hso_shared_int *mux)
-+{
-+ usb_free_urb(mux->shared_intr_urb);
-+ kfree(mux->shared_intr_buf);
-+ mutex_unlock(&mux->shared_int_lock);
-+ kfree(mux);
-+}
-+
-+static
-+struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface)
-+{
-+ struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL);
-+
-+ if (!mux)
-+ return NULL;
-+
-+ mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT,
-+ USB_DIR_IN);
-+ if (!mux->intr_endp) {
-+ dev_err(&interface->dev, "Can't find INT IN endpoint\n");
-+ goto exit;
-+ }
-+
-+ mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!mux->shared_intr_urb) {
-+ dev_err(&interface->dev, "Could not allocate intr urb?\n");
-+ goto exit;
-+ }
-+ mux->shared_intr_buf =
-+ kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize),
-+ GFP_KERNEL);
-+ if (!mux->shared_intr_buf)
-+ goto exit;
-+
-+ mutex_init(&mux->shared_int_lock);
-+
-+ return mux;
-+
-+exit:
-+ kfree(mux->shared_intr_buf);
-+ usb_free_urb(mux->shared_intr_urb);
-+ kfree(mux);
-+ return NULL;
-+}
-+
-+/* Gets the port spec for a certain interface */
-+static int hso_get_config_data(struct usb_interface *interface)
-+{
-+ struct usb_device *usbdev = interface_to_usbdev(interface);
-+ u8 *config_data = kmalloc(17, GFP_KERNEL);
-+ u32 if_num = interface->cur_altsetting->desc.bInterfaceNumber;
-+ s32 result;
-+
-+ if (!config_data)
-+ return -ENOMEM;
-+ if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
-+ 0x86, 0xC0, 0, 0, config_data, 17,
-+ USB_CTRL_SET_TIMEOUT) != 0x11) {
-+ kfree(config_data);
-+ return -EIO;
-+ }
-+
-+ switch (config_data[if_num]) {
-+ case 0x0:
-+ result = 0;
-+ break;
-+ case 0x1:
-+ result = HSO_PORT_DIAG;
-+ break;
-+ case 0x2:
-+ result = HSO_PORT_GPS;
-+ break;
-+ case 0x3:
-+ result = HSO_PORT_GPS_CONTROL;
-+ break;
-+ case 0x4:
-+ result = HSO_PORT_APP;
-+ break;
-+ case 0x5:
-+ result = HSO_PORT_APP2;
-+ break;
-+ case 0x6:
-+ result = HSO_PORT_CONTROL;
-+ break;
-+ case 0x7:
-+ result = HSO_PORT_NETWORK;
-+ break;
-+ case 0x8:
-+ result = HSO_PORT_MODEM;
-+ break;
-+ case 0x9:
-+ result = HSO_PORT_MSD;
-+ break;
-+ case 0xa:
-+ result = HSO_PORT_PCSC;
-+ break;
-+ case 0xb:
-+ result = HSO_PORT_VOICE;
-+ break;
-+ default:
-+ result = 0;
-+ }
-+
-+ if (result)
-+ result |= HSO_INTF_BULK;
-+
-+ if (config_data[16] & 0x1)
-+ result |= HSO_INFO_CRC_BUG;
-+
-+ kfree(config_data);
-+ return result;
-+}
-+
-+/* called once for each interface upon device insertion */
-+static int hso_probe(struct usb_interface *interface,
-+ const struct usb_device_id *id)
-+{
-+ int mux, i, if_num, port_spec;
-+ unsigned char port_mask;
-+ struct hso_device *hso_dev = NULL;
-+ struct hso_shared_int *shared_int;
-+ struct hso_device *tmp_dev = NULL;
-+
-+ if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
-+ dev_err(&interface->dev, "Not our interface\n");
-+ return -ENODEV;
-+ }
-+
-+ if_num = interface->cur_altsetting->desc.bInterfaceNumber;
-+
-+ /* Get the interface/port specification from either driver_info or from
-+ * the device itself */
-+ if (id->driver_info)
-+ port_spec = ((u32 *)(id->driver_info))[if_num];
-+ else
-+ port_spec = hso_get_config_data(interface);
-+
-+ /* Check if we need to switch to alt interfaces prior to port
-+ * configuration */
-+ if (interface->num_altsetting > 1)
-+ usb_set_interface(interface_to_usbdev(interface), if_num, 1);
-+ interface->needs_remote_wakeup = 1;
-+
-+ /* Allocate new hso device(s) */
-+ switch (port_spec & HSO_INTF_MASK) {
-+ case HSO_INTF_MUX:
-+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
-+ /* Create the network device */
-+ if (!disable_net) {
-+ hso_dev = hso_create_net_device(interface,
-+ port_spec);
-+ if (!hso_dev)
-+ goto exit;
-+ tmp_dev = hso_dev;
-+ }
-+ }
-+
-+ if (hso_get_mux_ports(interface, &port_mask))
-+ /* TODO: de-allocate everything */
-+ goto exit;
-+
-+ shared_int = hso_create_shared_int(interface);
-+ if (!shared_int)
-+ goto exit;
-+
-+ for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) {
-+ if (port_mask & i) {
-+ hso_dev = hso_create_mux_serial_device(
-+ interface, i, shared_int);
-+ if (!hso_dev)
-+ goto exit;
-+ }
-+ }
-+
-+ if (tmp_dev)
-+ hso_dev = tmp_dev;
-+ break;
-+
-+ case HSO_INTF_BULK:
-+ /* It's a regular bulk interface */
-+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
-+ if (!disable_net)
-+ hso_dev =
-+ hso_create_net_device(interface, port_spec);
-+ } else {
-+ hso_dev =
-+ hso_create_bulk_serial_device(interface, port_spec);
-+ }
-+ if (!hso_dev)
-+ goto exit;
-+ break;
-+ default:
-+ goto exit;
-+ }
-+
-+ /* save our data pointer in this device */
-+ usb_set_intfdata(interface, hso_dev);
-+
-+ /* done */
-+ return 0;
-+exit:
-+ hso_free_interface(interface);
-+ return -ENODEV;
-+}
-+
-+/* device removed, cleaning up */
-+static void hso_disconnect(struct usb_interface *interface)
-+{
-+ hso_free_interface(interface);
-+
-+ /* remove reference of our private data */
-+ usb_set_intfdata(interface, NULL);
-+}
-+
-+static void async_get_intf(struct work_struct *data)
-+{
-+ struct hso_device *hso_dev =
-+ container_of(data, struct hso_device, async_get_intf);
-+ usb_autopm_get_interface(hso_dev->interface);
-+}
-+
-+static void async_put_intf(struct work_struct *data)
-+{
-+ struct hso_device *hso_dev =
-+ container_of(data, struct hso_device, async_put_intf);
-+ usb_autopm_put_interface(hso_dev->interface);
-+}
-+
-+static int hso_get_activity(struct hso_device *hso_dev)
-+{
-+ if (hso_dev->usb->state == USB_STATE_SUSPENDED) {
-+ if (!hso_dev->is_active) {
-+ hso_dev->is_active = 1;
-+ schedule_work(&hso_dev->async_get_intf);
-+ }
-+ }
-+
-+ if (hso_dev->usb->state != USB_STATE_CONFIGURED)
-+ return -EAGAIN;
-+
-+ usb_mark_last_busy(hso_dev->usb);
-+
-+ return 0;
-+}
-+
-+static int hso_put_activity(struct hso_device *hso_dev)
-+{
-+ if (hso_dev->usb->state != USB_STATE_SUSPENDED) {
-+ if (hso_dev->is_active) {
-+ hso_dev->is_active = 0;
-+ schedule_work(&hso_dev->async_put_intf);
-+ return -EAGAIN;
-+ }
-+ }
-+ hso_dev->is_active = 0;
-+ return 0;
-+}
-+
-+/* called by kernel when we need to suspend device */
-+static int hso_suspend(struct usb_interface *iface, pm_message_t message)
-+{
-+ int i, result;
-+
-+ /* Stop all serial ports */
-+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
-+ if (serial_table[i] && (serial_table[i]->interface == iface)) {
-+ result = hso_stop_serial_device(serial_table[i]);
-+ if (result)
-+ goto out;
-+ }
-+ }
-+
-+ /* Stop all network ports */
-+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
-+ if (network_table[i] &&
-+ (network_table[i]->interface == iface)) {
-+ result = hso_stop_net_device(network_table[i]);
-+ if (result)
-+ goto out;
-+ }
-+ }
-+
-+out:
-+ return 0;
-+}
-+
-+/* called by kernel when we need to resume device */
-+static int hso_resume(struct usb_interface *iface)
-+{
-+ int i, result = 0;
-+ struct hso_net *hso_net;
-+
-+ /* Start all serial ports */
-+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
-+ if (serial_table[i] && (serial_table[i]->interface == iface)) {
-+ if (atomic_read(&dev2ser(serial_table[i])->port.count)) {
-+ result =
-+ hso_start_serial_device(serial_table[i], GFP_NOIO);
-+ hso_kick_transmit(dev2ser(serial_table[i]));
-+ if (result)
-+ goto out;
-+ }
-+ }
-+ }
-+
-+ /* Start all network ports */
-+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
-+ if (network_table[i] &&
-+ (network_table[i]->interface == iface)) {
-+ hso_net = dev2net(network_table[i]);
-+ if (hso_net->flags & IFF_UP) {
-+ /* First transmit any lingering data,
-+ then restart the device. */
-+ if (hso_net->skb_tx_buf) {
-+ dev_dbg(&iface->dev,
-+ "Transmitting"
-+ " lingering data\n");
-+ hso_net_start_xmit(hso_net->skb_tx_buf,
-+ hso_net->net);
-+ hso_net->skb_tx_buf = NULL;
-+ }
-+ result = hso_start_net_device(network_table[i]);
-+ if (result)
-+ goto out;
-+ }
-+ }
-+ }
-+
-+out:
-+ return result;
-+}
-+
-+static void hso_serial_ref_free(struct kref *ref)
-+{
-+ struct hso_device *hso_dev = container_of(ref, struct hso_device, ref);
-+
-+ hso_free_serial_device(hso_dev);
-+}
-+
-+static void hso_free_interface(struct usb_interface *interface)
-+{
-+ struct hso_serial *serial;
-+ int i;
-+
-+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
-+ if (serial_table[i] &&
-+ (serial_table[i]->interface == interface)) {
-+ serial = dev2ser(serial_table[i]);
-+ tty_port_tty_hangup(&serial->port, false);
-+ mutex_lock(&serial->parent->mutex);
-+ serial->parent->usb_gone = 1;
-+ mutex_unlock(&serial->parent->mutex);
-+ cancel_work_sync(&serial_table[i]->async_put_intf);
-+ cancel_work_sync(&serial_table[i]->async_get_intf);
-+ hso_serial_tty_unregister(serial);
-+ kref_put(&serial_table[i]->ref, hso_serial_ref_free);
-+ set_serial_by_index(i, NULL);
-+ }
-+ }
-+
-+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
-+ if (network_table[i] &&
-+ (network_table[i]->interface == interface)) {
-+ struct rfkill *rfk = dev2net(network_table[i])->rfkill;
-+ /* hso_stop_net_device doesn't stop the net queue since
-+ * traffic needs to start it again when suspended */
-+ netif_stop_queue(dev2net(network_table[i])->net);
-+ hso_stop_net_device(network_table[i]);
-+ cancel_work_sync(&network_table[i]->async_put_intf);
-+ cancel_work_sync(&network_table[i]->async_get_intf);
-+ if (rfk) {
-+ rfkill_unregister(rfk);
-+ rfkill_destroy(rfk);
-+ }
-+ hso_free_net_device(network_table[i]);
-+ }
-+ }
-+}
-+
-+/* Helper functions */
-+
-+/* Get the endpoint ! */
-+static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
-+ int type, int dir)
-+{
-+ int i;
-+ struct usb_host_interface *iface = intf->cur_altsetting;
-+ struct usb_endpoint_descriptor *endp;
-+
-+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
-+ endp = &iface->endpoint[i].desc;
-+ if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) &&
-+ (usb_endpoint_type(endp) == type))
-+ return endp;
-+ }
-+
-+ return NULL;
-+}
-+
-+/* Get the byte that describes which ports are enabled */
-+static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports)
-+{
-+ int i;
-+ struct usb_host_interface *iface = intf->cur_altsetting;
-+
-+ if (iface->extralen == 3) {
-+ *ports = iface->extra[2];
-+ return 0;
-+ }
-+
-+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
-+ if (iface->endpoint[i].extralen == 3) {
-+ *ports = iface->endpoint[i].extra[2];
-+ return 0;
-+ }
-+ }
-+
-+ return -1;
-+}
-+
-+/* interrupt urb needs to be submitted, used for serial read of muxed port */
-+static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int,
-+ struct usb_device *usb, gfp_t gfp)
-+{
-+ int result;
-+
-+ usb_fill_int_urb(shared_int->shared_intr_urb, usb,
-+ usb_rcvintpipe(usb,
-+ shared_int->intr_endp->bEndpointAddress & 0x7F),
-+ shared_int->shared_intr_buf,
-+ 1,
-+ intr_callback, shared_int,
-+ shared_int->intr_endp->bInterval);
-+
-+ result = usb_submit_urb(shared_int->shared_intr_urb, gfp);
-+ if (result)
-+ dev_warn(&usb->dev, "%s failed mux_intr_urb %d\n", __func__,
-+ result);
-+
-+ return result;
-+}
-+
-+/* operations setup of the serial interface */
-+static const struct tty_operations hso_serial_ops = {
-+ .open = hso_serial_open,
-+ .close = hso_serial_close,
-+ .write = hso_serial_write,
-+ .write_room = hso_serial_write_room,
-+ .cleanup = hso_serial_cleanup,
-+ .ioctl = hso_serial_ioctl,
-+ .set_termios = hso_serial_set_termios,
-+ .chars_in_buffer = hso_serial_chars_in_buffer,
-+ .tiocmget = hso_serial_tiocmget,
-+ .tiocmset = hso_serial_tiocmset,
-+ .get_icount = hso_get_count,
-+ .unthrottle = hso_unthrottle
-+};
-+
-+static struct usb_driver hso_driver = {
-+ .name = driver_name,
-+ .probe = hso_probe,
-+ .disconnect = hso_disconnect,
-+ .id_table = hso_ids,
-+ .suspend = hso_suspend,
-+ .resume = hso_resume,
-+ .reset_resume = hso_resume,
-+ .supports_autosuspend = 1,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+static int __init hso_init(void)
-+{
-+ int i;
-+ int result;
-+
-+ /* put it in the log */
-+ printk(KERN_INFO "hso: %s\n", version);
-+
-+ /* Initialise the serial table semaphore and table */
-+ spin_lock_init(&serial_table_lock);
-+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++)
-+ serial_table[i] = NULL;
-+
-+ /* allocate our driver using the proper amount of supported minors */
-+ tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS);
-+ if (!tty_drv)
-+ return -ENOMEM;
-+
-+ /* fill in all needed values */
-+ tty_drv->driver_name = driver_name;
-+ tty_drv->name = tty_filename;
-+
-+ /* if major number is provided as parameter, use that one */
-+ if (tty_major)
-+ tty_drv->major = tty_major;
-+
-+ tty_drv->minor_start = 0;
-+ tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-+ tty_drv->subtype = SERIAL_TYPE_NORMAL;
-+ tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-+ tty_drv->init_termios = tty_std_termios;
-+ hso_init_termios(&tty_drv->init_termios);
-+ tty_set_operations(tty_drv, &hso_serial_ops);
-+
-+ /* register the tty driver */
-+ result = tty_register_driver(tty_drv);
-+ if (result) {
-+ printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
-+ __func__, result);
-+ goto err_free_tty;
-+ }
-+
-+ /* register this module as an usb driver */
-+ result = usb_register(&hso_driver);
-+ if (result) {
-+ printk(KERN_ERR "Could not register hso driver? error: %d\n",
-+ result);
-+ goto err_unreg_tty;
-+ }
-+
-+ /* done */
-+ return 0;
-+err_unreg_tty:
-+ tty_unregister_driver(tty_drv);
-+err_free_tty:
-+ put_tty_driver(tty_drv);
-+ return result;
-+}
-+
-+static void __exit hso_exit(void)
-+{
-+ printk(KERN_INFO "hso: unloaded\n");
-+
-+ tty_unregister_driver(tty_drv);
-+ put_tty_driver(tty_drv);
-+ /* deregister the usb driver */
-+ usb_deregister(&hso_driver);
-+}
-+
-+/* Module definitions */
-+module_init(hso_init);
-+module_exit(hso_exit);
-+
-+MODULE_AUTHOR(MOD_AUTHOR);
-+MODULE_DESCRIPTION(MOD_DESCRIPTION);
-+MODULE_LICENSE(MOD_LICENSE);
-+
-+/* change the debug level (eg: insmod hso.ko debug=0x04) */
-+MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]");
-+module_param(debug, int, S_IRUGO | S_IWUSR);
-+
-+/* set the major tty number (eg: insmod hso.ko tty_major=245) */
-+MODULE_PARM_DESC(tty_major, "Set the major tty number");
-+module_param(tty_major, int, S_IRUGO | S_IWUSR);
-+
-+/* disable network interface (eg: insmod hso.ko disable_net=1) */
-+MODULE_PARM_DESC(disable_net, "Disable the network interface");
-+module_param(disable_net, int, S_IRUGO | S_IWUSR);
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/huawei_cdc_ncm.c backports-4.2.6-1/drivers/net/usb/huawei_cdc_ncm.c
---- backports-4.2.6-1.org/drivers/net/usb/huawei_cdc_ncm.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/huawei_cdc_ncm.c 2016-06-28 14:35:17.981973887 +0200
-@@ -0,0 +1,224 @@
-+/* huawei_cdc_ncm.c - handles Huawei devices using the CDC NCM protocol as
-+ * transport layer.
-+ * Copyright (C) 2013 Enrico Mioso <mrkiko.rs@gmail.com>
-+ *
-+ *
-+ * ABSTRACT:
-+ * This driver handles devices resembling the CDC NCM standard, but
-+ * encapsulating another protocol inside it. An example are some Huawei 3G
-+ * devices, exposing an embedded AT channel where you can set up the NCM
-+ * connection.
-+ * This code has been heavily inspired by the cdc_mbim.c driver, which is
-+ * Copyright (c) 2012 Smith Micro Software, Inc.
-+ * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/if_vlan.h>
-+#include <linux/ip.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/usb/cdc-wdm.h>
-+#include <linux/usb/cdc_ncm.h>
-+
-+/* Driver data */
-+struct huawei_cdc_ncm_state {
-+ struct cdc_ncm_ctx *ctx;
-+ atomic_t pmcount;
-+ struct usb_driver *subdriver;
-+ struct usb_interface *control;
-+ struct usb_interface *data;
-+};
-+
-+static int huawei_cdc_ncm_manage_power(struct usbnet *usbnet_dev, int on)
-+{
-+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
-+ int rv;
-+
-+ if ((on && atomic_add_return(1, &drvstate->pmcount) == 1) ||
-+ (!on && atomic_dec_and_test(&drvstate->pmcount))) {
-+ rv = usb_autopm_get_interface(usbnet_dev->intf);
-+ usbnet_dev->intf->needs_remote_wakeup = on;
-+ if (!rv)
-+ usb_autopm_put_interface(usbnet_dev->intf);
-+ }
-+ return 0;
-+}
-+
-+static int huawei_cdc_ncm_wdm_manage_power(struct usb_interface *intf,
-+ int status)
-+{
-+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
-+
-+ /* can be called while disconnecting */
-+ if (!usbnet_dev)
-+ return 0;
-+
-+ return huawei_cdc_ncm_manage_power(usbnet_dev, status);
-+}
-+
-+
-+static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev,
-+ struct usb_interface *intf)
-+{
-+ struct cdc_ncm_ctx *ctx;
-+ struct usb_driver *subdriver = ERR_PTR(-ENODEV);
-+ int ret = -ENODEV;
-+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
-+ int drvflags = 0;
-+
-+ /* altsetting should always be 1 for NCM devices - so we hard-coded
-+ * it here. Some huawei devices will need the NDP part of the NCM package to
-+ * be at the end of the frame.
-+ */
-+ drvflags |= CDC_NCM_FLAG_NDP_TO_END;
-+ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
-+ if (ret)
-+ goto err;
-+
-+ ctx = drvstate->ctx;
-+
-+ if (usbnet_dev->status)
-+ /* The wMaxCommand buffer must be big enough to hold
-+ * any message from the modem. Experience has shown
-+ * that some replies are more than 256 bytes long
-+ */
-+ subdriver = usb_cdc_wdm_register(ctx->control,
-+ &usbnet_dev->status->desc,
-+ 1024, /* wMaxCommand */
-+ huawei_cdc_ncm_wdm_manage_power);
-+ if (IS_ERR(subdriver)) {
-+ ret = PTR_ERR(subdriver);
-+ cdc_ncm_unbind(usbnet_dev, intf);
-+ goto err;
-+ }
-+
-+ /* Prevent usbnet from using the status descriptor */
-+ usbnet_dev->status = NULL;
-+
-+ drvstate->subdriver = subdriver;
-+
-+err:
-+ return ret;
-+}
-+
-+static void huawei_cdc_ncm_unbind(struct usbnet *usbnet_dev,
-+ struct usb_interface *intf)
-+{
-+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
-+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
-+
-+ if (drvstate->subdriver && drvstate->subdriver->disconnect)
-+ drvstate->subdriver->disconnect(ctx->control);
-+ drvstate->subdriver = NULL;
-+
-+ cdc_ncm_unbind(usbnet_dev, intf);
-+}
-+
-+static int huawei_cdc_ncm_suspend(struct usb_interface *intf,
-+ pm_message_t message)
-+{
-+ int ret = 0;
-+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
-+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
-+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
-+
-+ if (ctx == NULL) {
-+ ret = -ENODEV;
-+ goto error;
-+ }
-+
-+ ret = usbnet_suspend(intf, message);
-+ if (ret < 0)
-+ goto error;
-+
-+ if (intf == ctx->control &&
-+ drvstate->subdriver &&
-+ drvstate->subdriver->suspend)
-+ ret = drvstate->subdriver->suspend(intf, message);
-+ if (ret < 0)
-+ usbnet_resume(intf);
-+
-+error:
-+ return ret;
-+}
-+
-+static int huawei_cdc_ncm_resume(struct usb_interface *intf)
-+{
-+ int ret = 0;
-+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
-+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
-+ bool callsub;
-+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
-+
-+ /* should we call subdriver's resume function? */
-+ callsub =
-+ (intf == ctx->control &&
-+ drvstate->subdriver &&
-+ drvstate->subdriver->resume);
-+
-+ if (callsub)
-+ ret = drvstate->subdriver->resume(intf);
-+ if (ret < 0)
-+ goto err;
-+ ret = usbnet_resume(intf);
-+ if (ret < 0 && callsub)
-+ drvstate->subdriver->suspend(intf, PMSG_SUSPEND);
-+err:
-+ return ret;
-+}
-+
-+static const struct driver_info huawei_cdc_ncm_info = {
-+ .description = "Huawei CDC NCM device",
-+ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
-+ .bind = huawei_cdc_ncm_bind,
-+ .unbind = huawei_cdc_ncm_unbind,
-+ .manage_power = huawei_cdc_ncm_manage_power,
-+ .rx_fixup = cdc_ncm_rx_fixup,
-+ .tx_fixup = cdc_ncm_tx_fixup,
-+};
-+
-+static const struct usb_device_id huawei_cdc_ncm_devs[] = {
-+ /* Huawei NCM devices disguised as vendor specific */
-+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
-+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
-+ },
-+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
-+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
-+ },
-+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76),
-+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
-+ },
-+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x03, 0x16),
-+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
-+ },
-+
-+ /* Terminating entry */
-+ {
-+ },
-+};
-+MODULE_DEVICE_TABLE(usb, huawei_cdc_ncm_devs);
-+
-+static struct usb_driver huawei_cdc_ncm_driver = {
-+ .name = "huawei_cdc_ncm",
-+ .id_table = huawei_cdc_ncm_devs,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = huawei_cdc_ncm_suspend,
-+ .resume = huawei_cdc_ncm_resume,
-+ .reset_resume = huawei_cdc_ncm_resume,
-+ .supports_autosuspend = 1,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+module_usb_driver(huawei_cdc_ncm_driver);
-+MODULE_AUTHOR("Enrico Mioso <mrkiko.rs@gmail.com>");
-+MODULE_DESCRIPTION("USB CDC NCM host driver with encapsulated protocol support");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/int51x1.c backports-4.2.6-1/drivers/net/usb/int51x1.c
---- backports-4.2.6-1.org/drivers/net/usb/int51x1.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/int51x1.c 2016-06-28 14:35:17.985307220 +0200
-@@ -0,0 +1,199 @@
-+/*
-+ * Copyright (c) 2009 Peter Holik
-+ *
-+ * Intellon usb PLC (Powerline Communications) usb net driver
-+ *
-+ * http://www.tandel.be/downloads/INT51X1_Datasheet.pdf
-+ *
-+ * Based on the work of Jan 'RedBully' Seiffert
-+ */
-+
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or.
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/ctype.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/slab.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+
-+#define INT51X1_VENDOR_ID 0x09e1
-+#define INT51X1_PRODUCT_ID 0x5121
-+
-+#define INT51X1_HEADER_SIZE 2 /* 2 byte header */
-+
-+#define PACKET_TYPE_PROMISCUOUS (1 << 0)
-+#define PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
-+#define PACKET_TYPE_DIRECTED (1 << 2)
-+#define PACKET_TYPE_BROADCAST (1 << 3)
-+#define PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
-+
-+#define SET_ETHERNET_PACKET_FILTER 0x43
-+
-+static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ int len;
-+
-+ if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) {
-+ netdev_err(dev->net, "unexpected tiny rx frame\n");
-+ return 0;
-+ }
-+
-+ len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]);
-+
-+ skb_trim(skb, len);
-+
-+ return 1;
-+}
-+
-+static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev,
-+ struct sk_buff *skb, gfp_t flags)
-+{
-+ int pack_len = skb->len;
-+ int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE;
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+ int need_tail = 0;
-+ __le16 *len;
-+
-+ /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */
-+ if ((pack_with_header_len) < dev->maxpacket)
-+ need_tail = dev->maxpacket - pack_with_header_len + 1;
-+ /*
-+ * usbnet would send a ZLP if packetlength mod urbsize == 0 for us,
-+ * but we need to know ourself, because this would add to the length
-+ * we send down to the device...
-+ */
-+ else if (!(pack_with_header_len % dev->maxpacket))
-+ need_tail = 1;
-+
-+ if (!skb_cloned(skb) &&
-+ (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) {
-+ if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) {
-+ skb->data = memmove(skb->head + INT51X1_HEADER_SIZE,
-+ skb->data, skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ }
-+ } else {
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_copy_expand(skb,
-+ INT51X1_HEADER_SIZE,
-+ need_tail,
-+ flags);
-+ dev_kfree_skb_any(skb);
-+ if (!skb2)
-+ return NULL;
-+ skb = skb2;
-+ }
-+
-+ pack_len += need_tail;
-+ pack_len &= 0x07ff;
-+
-+ len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE);
-+ *len = cpu_to_le16(pack_len);
-+
-+ if(need_tail)
-+ memset(__skb_put(skb, need_tail), 0, need_tail);
-+
-+ return skb;
-+}
-+
-+static void int51x1_set_multicast(struct net_device *netdev)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u16 filter = PACKET_TYPE_DIRECTED | PACKET_TYPE_BROADCAST;
-+
-+ if (netdev->flags & IFF_PROMISC) {
-+ /* do not expect to see traffic of other PLCs */
-+ filter |= PACKET_TYPE_PROMISCUOUS;
-+ netdev_info(dev->net, "promiscuous mode enabled\n");
-+ } else if (!netdev_mc_empty(netdev) ||
-+ (netdev->flags & IFF_ALLMULTI)) {
-+ filter |= PACKET_TYPE_ALL_MULTICAST;
-+ netdev_dbg(dev->net, "receive all multicast enabled\n");
-+ } else {
-+ /* ~PROMISCUOUS, ~MULTICAST */
-+ netdev_dbg(dev->net, "receive own packets only\n");
-+ }
-+
-+ usbnet_write_cmd_async(dev, SET_ETHERNET_PACKET_FILTER,
-+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-+ filter, 0, NULL, 0);
-+}
-+
-+static const struct net_device_ops int51x1_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_set_rx_mode = int51x1_set_multicast,
-+};
-+
-+static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int status = usbnet_get_ethernet_addr(dev, 3);
-+
-+ if (status)
-+ return status;
-+
-+ dev->net->hard_header_len += INT51X1_HEADER_SIZE;
-+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-+ dev->net->netdev_ops = &int51x1_netdev_ops;
-+
-+ return usbnet_get_endpoints(dev, intf);
-+}
-+
-+static const struct driver_info int51x1_info = {
-+ .description = "Intellon usb powerline adapter",
-+ .bind = int51x1_bind,
-+ .rx_fixup = int51x1_rx_fixup,
-+ .tx_fixup = int51x1_tx_fixup,
-+ .in = 1,
-+ .out = 2,
-+ .flags = FLAG_ETHER,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID),
-+ .driver_info = (unsigned long) &int51x1_info,
-+ },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver int51x1_driver = {
-+ .name = "int51x1",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(int51x1_driver);
-+
-+MODULE_AUTHOR("Peter Holik");
-+MODULE_DESCRIPTION("Intellon usb powerline adapter");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/ipheth.c backports-4.2.6-1/drivers/net/usb/ipheth.c
---- backports-4.2.6-1.org/drivers/net/usb/ipheth.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/ipheth.c 2016-06-28 14:35:17.985307220 +0200
-@@ -0,0 +1,588 @@
-+/*
-+ * ipheth.c - Apple iPhone USB Ethernet driver
-+ *
-+ * Copyright (c) 2009 Diego Giagio <diego@giagio.com>
-+ * All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ * notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ * notice, this list of conditions and the following disclaimer in the
-+ * documentation and/or other materials provided with the distribution.
-+ * 3. Neither the name of GIAGIO.COM nor the names of its contributors
-+ * may be used to endorse or promote products derived from this software
-+ * without specific prior written permission.
-+ *
-+ * Alternatively, provided that this notice is retained in full, this
-+ * software may be distributed under the terms of the GNU General
-+ * Public License ("GPL") version 2, in which case the provisions of the
-+ * GPL apply INSTEAD OF those given above.
-+ *
-+ * The provided data structures and external interfaces from this code
-+ * are not restricted to be used by modules with a GPL compatible license.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ *
-+ *
-+ * Attention: iPhone device must be paired, otherwise it won't respond to our
-+ * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/usb.h>
-+#include <linux/workqueue.h>
-+
-+#define USB_VENDOR_APPLE 0x05ac
-+#define USB_PRODUCT_IPHONE 0x1290
-+#define USB_PRODUCT_IPHONE_3G 0x1292
-+#define USB_PRODUCT_IPHONE_3GS 0x1294
-+#define USB_PRODUCT_IPHONE_4 0x1297
-+#define USB_PRODUCT_IPAD 0x129a
-+#define USB_PRODUCT_IPAD_2 0x12a2
-+#define USB_PRODUCT_IPAD_3 0x12a6
-+#define USB_PRODUCT_IPAD_MINI 0x12ab
-+#define USB_PRODUCT_IPHONE_4_VZW 0x129c
-+#define USB_PRODUCT_IPHONE_4S 0x12a0
-+#define USB_PRODUCT_IPHONE_5 0x12a8
-+
-+#define IPHETH_USBINTF_CLASS 255
-+#define IPHETH_USBINTF_SUBCLASS 253
-+#define IPHETH_USBINTF_PROTO 1
-+
-+#define IPHETH_BUF_SIZE 1516
-+#define IPHETH_IP_ALIGN 2 /* padding at front of URB */
-+#define IPHETH_TX_TIMEOUT (5 * HZ)
-+
-+#define IPHETH_INTFNUM 2
-+#define IPHETH_ALT_INTFNUM 1
-+
-+#define IPHETH_CTRL_ENDP 0x00
-+#define IPHETH_CTRL_BUF_SIZE 0x40
-+#define IPHETH_CTRL_TIMEOUT (5 * HZ)
-+
-+#define IPHETH_CMD_GET_MACADDR 0x00
-+#define IPHETH_CMD_CARRIER_CHECK 0x45
-+
-+#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ)
-+#define IPHETH_CARRIER_ON 0x04
-+
-+static struct usb_device_id ipheth_table[] = {
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPAD,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPAD_2,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPAD_3,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPAD_MINI,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { USB_DEVICE_AND_INTERFACE_INFO(
-+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_5,
-+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
-+ IPHETH_USBINTF_PROTO) },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(usb, ipheth_table);
-+
-+struct ipheth_device {
-+ struct usb_device *udev;
-+ struct usb_interface *intf;
-+ struct net_device *net;
-+ struct sk_buff *tx_skb;
-+ struct urb *tx_urb;
-+ struct urb *rx_urb;
-+ unsigned char *tx_buf;
-+ unsigned char *rx_buf;
-+ unsigned char *ctrl_buf;
-+ u8 bulk_in;
-+ u8 bulk_out;
-+ struct delayed_work carrier_work;
-+};
-+
-+static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
-+
-+static int ipheth_alloc_urbs(struct ipheth_device *iphone)
-+{
-+ struct urb *tx_urb = NULL;
-+ struct urb *rx_urb = NULL;
-+ u8 *tx_buf = NULL;
-+ u8 *rx_buf = NULL;
-+
-+ tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (tx_urb == NULL)
-+ goto error_nomem;
-+
-+ rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (rx_urb == NULL)
-+ goto free_tx_urb;
-+
-+ tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
-+ GFP_KERNEL, &tx_urb->transfer_dma);
-+ if (tx_buf == NULL)
-+ goto free_rx_urb;
-+
-+ rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE,
-+ GFP_KERNEL, &rx_urb->transfer_dma);
-+ if (rx_buf == NULL)
-+ goto free_tx_buf;
-+
-+
-+ iphone->tx_urb = tx_urb;
-+ iphone->rx_urb = rx_urb;
-+ iphone->tx_buf = tx_buf;
-+ iphone->rx_buf = rx_buf;
-+ return 0;
-+
-+free_tx_buf:
-+ usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf,
-+ tx_urb->transfer_dma);
-+free_rx_urb:
-+ usb_free_urb(rx_urb);
-+free_tx_urb:
-+ usb_free_urb(tx_urb);
-+error_nomem:
-+ return -ENOMEM;
-+}
-+
-+static void ipheth_free_urbs(struct ipheth_device *iphone)
-+{
-+ usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf,
-+ iphone->rx_urb->transfer_dma);
-+ usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf,
-+ iphone->tx_urb->transfer_dma);
-+ usb_free_urb(iphone->rx_urb);
-+ usb_free_urb(iphone->tx_urb);
-+}
-+
-+static void ipheth_kill_urbs(struct ipheth_device *dev)
-+{
-+ usb_kill_urb(dev->tx_urb);
-+ usb_kill_urb(dev->rx_urb);
-+}
-+
-+static void ipheth_rcvbulk_callback(struct urb *urb)
-+{
-+ struct ipheth_device *dev;
-+ struct sk_buff *skb;
-+ int status;
-+ char *buf;
-+ int len;
-+
-+ dev = urb->context;
-+ if (dev == NULL)
-+ return;
-+
-+ status = urb->status;
-+ switch (status) {
-+ case -ENOENT:
-+ case -ECONNRESET:
-+ case -ESHUTDOWN:
-+ return;
-+ case 0:
-+ break;
-+ default:
-+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
-+ __func__, status);
-+ return;
-+ }
-+
-+ if (urb->actual_length <= IPHETH_IP_ALIGN) {
-+ dev->net->stats.rx_length_errors++;
-+ return;
-+ }
-+ len = urb->actual_length - IPHETH_IP_ALIGN;
-+ buf = urb->transfer_buffer + IPHETH_IP_ALIGN;
-+
-+ skb = dev_alloc_skb(len);
-+ if (!skb) {
-+ dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
-+ __func__);
-+ dev->net->stats.rx_dropped++;
-+ return;
-+ }
-+
-+ memcpy(skb_put(skb, len), buf, len);
-+ skb->dev = dev->net;
-+ skb->protocol = eth_type_trans(skb, dev->net);
-+
-+ dev->net->stats.rx_packets++;
-+ dev->net->stats.rx_bytes += len;
-+
-+ netif_rx(skb);
-+ ipheth_rx_submit(dev, GFP_ATOMIC);
-+}
-+
-+static void ipheth_sndbulk_callback(struct urb *urb)
-+{
-+ struct ipheth_device *dev;
-+ int status = urb->status;
-+
-+ dev = urb->context;
-+ if (dev == NULL)
-+ return;
-+
-+ if (status != 0 &&
-+ status != -ENOENT &&
-+ status != -ECONNRESET &&
-+ status != -ESHUTDOWN)
-+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
-+ __func__, status);
-+
-+ dev_kfree_skb_irq(dev->tx_skb);
-+ netif_wake_queue(dev->net);
-+}
-+
-+static int ipheth_carrier_set(struct ipheth_device *dev)
-+{
-+ struct usb_device *udev = dev->udev;
-+ int retval;
-+
-+ retval = usb_control_msg(udev,
-+ usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
-+ IPHETH_CMD_CARRIER_CHECK, /* request */
-+ 0xc0, /* request type */
-+ 0x00, /* value */
-+ 0x02, /* index */
-+ dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
-+ IPHETH_CTRL_TIMEOUT);
-+ if (retval < 0) {
-+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
-+ __func__, retval);
-+ return retval;
-+ }
-+
-+ if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON)
-+ netif_carrier_on(dev->net);
-+ else
-+ netif_carrier_off(dev->net);
-+
-+ return 0;
-+}
-+
-+static void ipheth_carrier_check_work(struct work_struct *work)
-+{
-+ struct ipheth_device *dev = container_of(work, struct ipheth_device,
-+ carrier_work.work);
-+
-+ ipheth_carrier_set(dev);
-+ schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
-+}
-+
-+static int ipheth_get_macaddr(struct ipheth_device *dev)
-+{
-+ struct usb_device *udev = dev->udev;
-+ struct net_device *net = dev->net;
-+ int retval;
-+
-+ retval = usb_control_msg(udev,
-+ usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
-+ IPHETH_CMD_GET_MACADDR, /* request */
-+ 0xc0, /* request type */
-+ 0x00, /* value */
-+ 0x02, /* index */
-+ dev->ctrl_buf,
-+ IPHETH_CTRL_BUF_SIZE,
-+ IPHETH_CTRL_TIMEOUT);
-+ if (retval < 0) {
-+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
-+ __func__, retval);
-+ } else if (retval < ETH_ALEN) {
-+ dev_err(&dev->intf->dev,
-+ "%s: usb_control_msg: short packet: %d bytes\n",
-+ __func__, retval);
-+ retval = -EINVAL;
-+ } else {
-+ memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN);
-+ retval = 0;
-+ }
-+
-+ return retval;
-+}
-+
-+static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
-+{
-+ struct usb_device *udev = dev->udev;
-+ int retval;
-+
-+ usb_fill_bulk_urb(dev->rx_urb, udev,
-+ usb_rcvbulkpipe(udev, dev->bulk_in),
-+ dev->rx_buf, IPHETH_BUF_SIZE,
-+ ipheth_rcvbulk_callback,
-+ dev);
-+ dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-+
-+ retval = usb_submit_urb(dev->rx_urb, mem_flags);
-+ if (retval)
-+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
-+ __func__, retval);
-+ return retval;
-+}
-+
-+static int ipheth_open(struct net_device *net)
-+{
-+ struct ipheth_device *dev = netdev_priv(net);
-+ struct usb_device *udev = dev->udev;
-+ int retval = 0;
-+
-+ usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM);
-+
-+ retval = ipheth_carrier_set(dev);
-+ if (retval)
-+ return retval;
-+
-+ retval = ipheth_rx_submit(dev, GFP_KERNEL);
-+ if (retval)
-+ return retval;
-+
-+ schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
-+ netif_start_queue(net);
-+ return retval;
-+}
-+
-+static int ipheth_close(struct net_device *net)
-+{
-+ struct ipheth_device *dev = netdev_priv(net);
-+
-+ cancel_delayed_work_sync(&dev->carrier_work);
-+ netif_stop_queue(net);
-+ return 0;
-+}
-+
-+static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
-+{
-+ struct ipheth_device *dev = netdev_priv(net);
-+ struct usb_device *udev = dev->udev;
-+ int retval;
-+
-+ /* Paranoid */
-+ if (skb->len > IPHETH_BUF_SIZE) {
-+ WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len);
-+ dev->net->stats.tx_dropped++;
-+ dev_kfree_skb_irq(skb);
-+ return NETDEV_TX_OK;
-+ }
-+
-+ memcpy(dev->tx_buf, skb->data, skb->len);
-+ if (skb->len < IPHETH_BUF_SIZE)
-+ memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len);
-+
-+ usb_fill_bulk_urb(dev->tx_urb, udev,
-+ usb_sndbulkpipe(udev, dev->bulk_out),
-+ dev->tx_buf, IPHETH_BUF_SIZE,
-+ ipheth_sndbulk_callback,
-+ dev);
-+ dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-+
-+ retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
-+ if (retval) {
-+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
-+ __func__, retval);
-+ dev->net->stats.tx_errors++;
-+ dev_kfree_skb_irq(skb);
-+ } else {
-+ dev->tx_skb = skb;
-+
-+ dev->net->stats.tx_packets++;
-+ dev->net->stats.tx_bytes += skb->len;
-+ netif_stop_queue(net);
-+ }
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+static void ipheth_tx_timeout(struct net_device *net)
-+{
-+ struct ipheth_device *dev = netdev_priv(net);
-+
-+ dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
-+ dev->net->stats.tx_errors++;
-+ usb_unlink_urb(dev->tx_urb);
-+}
-+
-+static u32 ipheth_ethtool_op_get_link(struct net_device *net)
-+{
-+ struct ipheth_device *dev = netdev_priv(net);
-+ return netif_carrier_ok(dev->net);
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_link = ipheth_ethtool_op_get_link
-+};
-+
-+static const struct net_device_ops ipheth_netdev_ops = {
-+ .ndo_open = ipheth_open,
-+ .ndo_stop = ipheth_close,
-+ .ndo_start_xmit = ipheth_tx,
-+ .ndo_tx_timeout = ipheth_tx_timeout,
-+};
-+
-+static int ipheth_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_device *udev = interface_to_usbdev(intf);
-+ struct usb_host_interface *hintf;
-+ struct usb_endpoint_descriptor *endp;
-+ struct ipheth_device *dev;
-+ struct net_device *netdev;
-+ int i;
-+ int retval;
-+
-+ netdev = alloc_etherdev(sizeof(struct ipheth_device));
-+ if (!netdev)
-+ return -ENOMEM;
-+
-+ netdev->netdev_ops = &ipheth_netdev_ops;
-+ netdev->watchdog_timeo = IPHETH_TX_TIMEOUT;
-+ strcpy(netdev->name, "eth%d");
-+
-+ dev = netdev_priv(netdev);
-+ dev->udev = udev;
-+ dev->net = netdev;
-+ dev->intf = intf;
-+
-+ /* Set up endpoints */
-+ hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
-+ if (hintf == NULL) {
-+ retval = -ENODEV;
-+ dev_err(&intf->dev, "Unable to find alternate settings interface\n");
-+ goto err_endpoints;
-+ }
-+
-+ for (i = 0; i < hintf->desc.bNumEndpoints; i++) {
-+ endp = &hintf->endpoint[i].desc;
-+ if (usb_endpoint_is_bulk_in(endp))
-+ dev->bulk_in = endp->bEndpointAddress;
-+ else if (usb_endpoint_is_bulk_out(endp))
-+ dev->bulk_out = endp->bEndpointAddress;
-+ }
-+ if (!(dev->bulk_in && dev->bulk_out)) {
-+ retval = -ENODEV;
-+ dev_err(&intf->dev, "Unable to find endpoints\n");
-+ goto err_endpoints;
-+ }
-+
-+ dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL);
-+ if (dev->ctrl_buf == NULL) {
-+ retval = -ENOMEM;
-+ goto err_alloc_ctrl_buf;
-+ }
-+
-+ retval = ipheth_get_macaddr(dev);
-+ if (retval)
-+ goto err_get_macaddr;
-+
-+ INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work);
-+
-+ retval = ipheth_alloc_urbs(dev);
-+ if (retval) {
-+ dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
-+ goto err_alloc_urbs;
-+ }
-+
-+ usb_set_intfdata(intf, dev);
-+
-+ SET_NETDEV_DEV(netdev, &intf->dev);
-+ netdev->ethtool_ops = &ops;
-+
-+ retval = register_netdev(netdev);
-+ if (retval) {
-+ dev_err(&intf->dev, "error registering netdev: %d\n", retval);
-+ retval = -EIO;
-+ goto err_register_netdev;
-+ }
-+
-+ dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
-+ return 0;
-+
-+err_register_netdev:
-+ ipheth_free_urbs(dev);
-+err_alloc_urbs:
-+err_get_macaddr:
-+err_alloc_ctrl_buf:
-+ kfree(dev->ctrl_buf);
-+err_endpoints:
-+ free_netdev(netdev);
-+ return retval;
-+}
-+
-+static void ipheth_disconnect(struct usb_interface *intf)
-+{
-+ struct ipheth_device *dev;
-+
-+ dev = usb_get_intfdata(intf);
-+ if (dev != NULL) {
-+ unregister_netdev(dev->net);
-+ ipheth_kill_urbs(dev);
-+ ipheth_free_urbs(dev);
-+ kfree(dev->ctrl_buf);
-+ free_netdev(dev->net);
-+ }
-+ usb_set_intfdata(intf, NULL);
-+ dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n");
-+}
-+
-+static struct usb_driver ipheth_driver = {
-+ .name = "ipheth",
-+ .probe = ipheth_probe,
-+ .disconnect = ipheth_disconnect,
-+ .id_table = ipheth_table,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(ipheth_driver);
-+
-+MODULE_AUTHOR("Diego Giagio <diego@giagio.com>");
-+MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/kalmia.c backports-4.2.6-1/drivers/net/usb/kalmia.c
---- backports-4.2.6-1.org/drivers/net/usb/kalmia.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/kalmia.c 2016-06-28 14:35:17.985307220 +0200
-@@ -0,0 +1,366 @@
-+/*
-+ * USB network interface driver for Samsung Kalmia based LTE USB modem like the
-+ * Samsung GT-B3730 and GT-B3710.
-+ *
-+ * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com>
-+ *
-+ * Sponsored by Quicklink Video Distribution Services Ltd.
-+ *
-+ * Based on the cdc_eem module.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ctype.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/gfp.h>
-+
-+/*
-+ * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control
-+ * handled by the "option" module and an ethernet data port handled by this
-+ * module.
-+ *
-+ * The stick must first be switched into modem mode by usb_modeswitch
-+ * or similar tool. Then the modem gets sent two initialization packets by
-+ * this module, which gives the MAC address of the device. User space can then
-+ * connect the modem using AT commands through the ACM port and then use
-+ * DHCP on the network interface exposed by this module. Network packets are
-+ * sent to and from the modem in a proprietary format discovered after watching
-+ * the behavior of the windows driver for the modem.
-+ *
-+ * More information about the use of the modem is available in usb_modeswitch
-+ * forum and the project page:
-+ *
-+ * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465
-+ * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver
-+ */
-+
-+/* #define DEBUG */
-+/* #define VERBOSE */
-+
-+#define KALMIA_HEADER_LENGTH 6
-+#define KALMIA_ALIGN_SIZE 4
-+#define KALMIA_USB_TIMEOUT 10000
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int
-+kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len,
-+ u8 *buffer, u8 expected_len)
-+{
-+ int act_len;
-+ int status;
-+
-+ netdev_dbg(dev->net, "Sending init packet");
-+
-+ status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02),
-+ init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT);
-+ if (status != 0) {
-+ netdev_err(dev->net,
-+ "Error sending init packet. Status %i, length %i\n",
-+ status, act_len);
-+ return status;
-+ }
-+ else if (act_len != init_msg_len) {
-+ netdev_err(dev->net,
-+ "Did not send all of init packet. Bytes sent: %i",
-+ act_len);
-+ }
-+ else {
-+ netdev_dbg(dev->net, "Successfully sent init packet.");
-+ }
-+
-+ status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81),
-+ buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT);
-+
-+ if (status != 0)
-+ netdev_err(dev->net,
-+ "Error receiving init result. Status %i, length %i\n",
-+ status, act_len);
-+ else if (act_len != expected_len)
-+ netdev_err(dev->net, "Unexpected init result length: %i\n",
-+ act_len);
-+
-+ return status;
-+}
-+
-+static int
-+kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr)
-+{
-+ static const char init_msg_1[] =
-+ { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
-+ 0x00, 0x00 };
-+ static const char init_msg_2[] =
-+ { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4,
-+ 0x00, 0x00 };
-+ static const int buflen = 28;
-+ char *usb_buf;
-+ int status;
-+
-+ usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL);
-+ if (!usb_buf)
-+ return -ENOMEM;
-+
-+ memcpy(usb_buf, init_msg_1, 12);
-+ status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1)
-+ / sizeof(init_msg_1[0]), usb_buf, 24);
-+ if (status != 0)
-+ return status;
-+
-+ memcpy(usb_buf, init_msg_2, 12);
-+ status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2)
-+ / sizeof(init_msg_2[0]), usb_buf, 28);
-+ if (status != 0)
-+ return status;
-+
-+ memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN);
-+
-+ kfree(usb_buf);
-+ return status;
-+}
-+
-+static int
-+kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int status;
-+ u8 ethernet_addr[ETH_ALEN];
-+
-+ /* Don't bind to AT command interface */
-+ if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
-+ return -EINVAL;
-+
-+ dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK);
-+ dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK);
-+ dev->status = NULL;
-+
-+ dev->net->hard_header_len += KALMIA_HEADER_LENGTH;
-+ dev->hard_mtu = 1400;
-+ dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing
-+
-+ status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr);
-+
-+ if (status < 0) {
-+ usb_set_intfdata(intf, NULL);
-+ usb_driver_release_interface(driver_of(intf), intf);
-+ return status;
-+ }
-+
-+ memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN);
-+
-+ return status;
-+}
-+
-+static struct sk_buff *
-+kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
-+{
-+ struct sk_buff *skb2 = NULL;
-+ u16 content_len;
-+ unsigned char *header_start;
-+ unsigned char ether_type_1, ether_type_2;
-+ u8 remainder, padlen = 0;
-+
-+ if (!skb_cloned(skb)) {
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+
-+ if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom
-+ >= KALMIA_HEADER_LENGTH))
-+ goto done;
-+
-+ if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH
-+ + KALMIA_ALIGN_SIZE)) {
-+ skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH,
-+ skb->data, skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ goto done;
-+ }
-+ }
-+
-+ skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH,
-+ KALMIA_ALIGN_SIZE, flags);
-+ if (!skb2)
-+ return NULL;
-+
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+
-+done:
-+ header_start = skb_push(skb, KALMIA_HEADER_LENGTH);
-+ ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12];
-+ ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13];
-+
-+ netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1,
-+ ether_type_2);
-+
-+ /* According to empiric data for data packages */
-+ header_start[0] = 0x57;
-+ header_start[1] = 0x44;
-+ content_len = skb->len - KALMIA_HEADER_LENGTH;
-+
-+ put_unaligned_le16(content_len, &header_start[2]);
-+ header_start[4] = ether_type_1;
-+ header_start[5] = ether_type_2;
-+
-+ /* Align to 4 bytes by padding with zeros */
-+ remainder = skb->len % KALMIA_ALIGN_SIZE;
-+ if (remainder > 0) {
-+ padlen = KALMIA_ALIGN_SIZE - remainder;
-+ memset(skb_put(skb, padlen), 0, padlen);
-+ }
-+
-+ netdev_dbg(dev->net,
-+ "Sending package with length %i and padding %i. Header: %6phC.",
-+ content_len, padlen, header_start);
-+
-+ return skb;
-+}
-+
-+static int
-+kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ /*
-+ * Our task here is to strip off framing, leaving skb with one
-+ * data frame for the usbnet framework code to process.
-+ */
-+ static const u8 HEADER_END_OF_USB_PACKET[] =
-+ { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 };
-+ static const u8 EXPECTED_UNKNOWN_HEADER_1[] =
-+ { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 };
-+ static const u8 EXPECTED_UNKNOWN_HEADER_2[] =
-+ { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 };
-+ int i = 0;
-+
-+ /* incomplete header? */
-+ if (skb->len < KALMIA_HEADER_LENGTH)
-+ return 0;
-+
-+ do {
-+ struct sk_buff *skb2 = NULL;
-+ u8 *header_start;
-+ u16 usb_packet_length, ether_packet_length;
-+ int is_last;
-+
-+ header_start = skb->data;
-+
-+ if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) {
-+ if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1,
-+ sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp(
-+ header_start, EXPECTED_UNKNOWN_HEADER_2,
-+ sizeof(EXPECTED_UNKNOWN_HEADER_2))) {
-+ netdev_dbg(dev->net,
-+ "Received expected unknown frame header: %6phC. Package length: %i\n",
-+ header_start,
-+ skb->len - KALMIA_HEADER_LENGTH);
-+ }
-+ else {
-+ netdev_err(dev->net,
-+ "Received unknown frame header: %6phC. Package length: %i\n",
-+ header_start,
-+ skb->len - KALMIA_HEADER_LENGTH);
-+ return 0;
-+ }
-+ }
-+ else
-+ netdev_dbg(dev->net,
-+ "Received header: %6phC. Package length: %i\n",
-+ header_start, skb->len - KALMIA_HEADER_LENGTH);
-+
-+ /* subtract start header and end header */
-+ usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH);
-+ ether_packet_length = get_unaligned_le16(&header_start[2]);
-+ skb_pull(skb, KALMIA_HEADER_LENGTH);
-+
-+ /* Some small packets misses end marker */
-+ if (usb_packet_length < ether_packet_length) {
-+ ether_packet_length = usb_packet_length
-+ + KALMIA_HEADER_LENGTH;
-+ is_last = true;
-+ }
-+ else {
-+ netdev_dbg(dev->net, "Correct package length #%i", i
-+ + 1);
-+
-+ is_last = (memcmp(skb->data + ether_packet_length,
-+ HEADER_END_OF_USB_PACKET,
-+ sizeof(HEADER_END_OF_USB_PACKET)) == 0);
-+ if (!is_last) {
-+ header_start = skb->data + ether_packet_length;
-+ netdev_dbg(dev->net,
-+ "End header: %6phC. Package length: %i\n",
-+ header_start,
-+ skb->len - KALMIA_HEADER_LENGTH);
-+ }
-+ }
-+
-+ if (is_last) {
-+ skb2 = skb;
-+ }
-+ else {
-+ skb2 = skb_clone(skb, GFP_ATOMIC);
-+ if (unlikely(!skb2))
-+ return 0;
-+ }
-+
-+ skb_trim(skb2, ether_packet_length);
-+
-+ if (is_last) {
-+ return 1;
-+ }
-+ else {
-+ usbnet_skb_return(dev, skb2);
-+ skb_pull(skb, ether_packet_length);
-+ }
-+
-+ i++;
-+ }
-+ while (skb->len);
-+
-+ return 1;
-+}
-+
-+static const struct driver_info kalmia_info = {
-+ .description = "Samsung Kalmia LTE USB dongle",
-+ .flags = FLAG_WWAN,
-+ .bind = kalmia_bind,
-+ .rx_fixup = kalmia_rx_fixup,
-+ .tx_fixup = kalmia_tx_fixup
-+};
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static const struct usb_device_id products[] = {
-+ /* The unswitched USB ID, to get the module auto loaded: */
-+ { USB_DEVICE(0x04e8, 0x689a) },
-+ /* The stick swithed into modem (by e.g. usb_modeswitch): */
-+ { USB_DEVICE(0x04e8, 0x6889),
-+ .driver_info = (unsigned long) &kalmia_info, },
-+ { /* EMPTY == end of list */} };
-+MODULE_DEVICE_TABLE( usb, products);
-+
-+static struct usb_driver kalmia_driver = {
-+ .name = "kalmia",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(kalmia_driver);
-+
-+MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>");
-+MODULE_DESCRIPTION("Samsung Kalmia USB network driver");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/kaweth.c backports-4.2.6-1/drivers/net/usb/kaweth.c
---- backports-4.2.6-1.org/drivers/net/usb/kaweth.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/kaweth.c 2016-06-28 14:35:17.988640553 +0200
-@@ -0,0 +1,1331 @@
-+/****************************************************************
-+ *
-+ * kaweth.c - driver for KL5KUSB101 based USB->Ethernet
-+ *
-+ * (c) 2000 Interlan Communications
-+ * (c) 2000 Stephane Alnet
-+ * (C) 2001 Brad Hards
-+ * (C) 2002 Oliver Neukum
-+ *
-+ * Original author: The Zapman <zapman@interlan.net>
-+ * Inspired by, and much credit goes to Michael Rothwell
-+ * <rothwell@interlan.net> for the test equipment, help, and patience
-+ * Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
-+ * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
-+ * for providing the firmware and driver resources.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ ****************************************************************/
-+
-+/* TODO:
-+ * Develop test procedures for USB net interfaces
-+ * Run test procedures
-+ * Fix bugs from previous two steps
-+ * Snoop other OSs for any tricks we're not doing
-+ * Reduce arbitrary timeouts
-+ * Smart multicast support
-+ * Temporary MAC change support
-+ * Tunable SOFs parameter - ioctl()?
-+ * Ethernet stats collection
-+ * Code formatting improvements
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/delay.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/usb.h>
-+#include <linux/types.h>
-+#include <linux/ethtool.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/wait.h>
-+#include <linux/firmware.h>
-+#include <asm/uaccess.h>
-+#include <asm/byteorder.h>
-+
-+#undef DEBUG
-+
-+#define KAWETH_MTU 1514
-+#define KAWETH_BUF_SIZE 1664
-+#define KAWETH_TX_TIMEOUT (5 * HZ)
-+#define KAWETH_SCRATCH_SIZE 32
-+#define KAWETH_FIRMWARE_BUF_SIZE 4096
-+#define KAWETH_CONTROL_TIMEOUT (30000)
-+
-+#define KAWETH_STATUS_BROKEN 0x0000001
-+#define KAWETH_STATUS_CLOSING 0x0000002
-+#define KAWETH_STATUS_SUSPENDING 0x0000004
-+
-+#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
-+
-+#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
-+#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
-+#define KAWETH_PACKET_FILTER_DIRECTED 0x04
-+#define KAWETH_PACKET_FILTER_BROADCAST 0x08
-+#define KAWETH_PACKET_FILTER_MULTICAST 0x10
-+
-+/* Table 7 */
-+#define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00
-+#define KAWETH_COMMAND_MULTICAST_FILTERS 0x01
-+#define KAWETH_COMMAND_SET_PACKET_FILTER 0x02
-+#define KAWETH_COMMAND_STATISTICS 0x03
-+#define KAWETH_COMMAND_SET_TEMP_MAC 0x06
-+#define KAWETH_COMMAND_GET_TEMP_MAC 0x07
-+#define KAWETH_COMMAND_SET_URB_SIZE 0x08
-+#define KAWETH_COMMAND_SET_SOFS_WAIT 0x09
-+#define KAWETH_COMMAND_SCAN 0xFF
-+
-+#define KAWETH_SOFS_TO_WAIT 0x05
-+
-+#define INTBUFFERSIZE 4
-+
-+#define STATE_OFFSET 0
-+#define STATE_MASK 0x40
-+#define STATE_SHIFT 5
-+
-+#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
-+
-+
-+MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
-+MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
-+MODULE_LICENSE("GPL");
-+MODULE_FIRMWARE("kaweth/new_code.bin");
-+MODULE_FIRMWARE("kaweth/new_code_fix.bin");
-+MODULE_FIRMWARE("kaweth/trigger_code.bin");
-+MODULE_FIRMWARE("kaweth/trigger_code_fix.bin");
-+
-+static const char driver_name[] = "kaweth";
-+
-+static int kaweth_probe(
-+ struct usb_interface *intf,
-+ const struct usb_device_id *id /* from id_table */
-+ );
-+static void kaweth_disconnect(struct usb_interface *intf);
-+static int kaweth_internal_control_msg(struct usb_device *usb_dev,
-+ unsigned int pipe,
-+ struct usb_ctrlrequest *cmd, void *data,
-+ int len, int timeout);
-+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
-+static int kaweth_resume(struct usb_interface *intf);
-+
-+/****************************************************************
-+ * usb_device_id
-+ ****************************************************************/
-+static struct usb_device_id usb_klsi_table[] = {
-+ { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
-+ { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
-+ { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
-+ { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */
-+ { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
-+ { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
-+ { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
-+ { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
-+ { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
-+ { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
-+ { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
-+ { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
-+ { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
-+ { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
-+ { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
-+ { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
-+ { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
-+ { USB_DEVICE(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */
-+ { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
-+ { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
-+ { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */
-+ { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */
-+ { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */
-+ { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */
-+ { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */
-+ { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
-+ { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
-+ { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
-+ { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */
-+ { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */
-+ { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
-+ { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
-+ { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
-+ { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */
-+ { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
-+ {} /* Null terminator */
-+};
-+
-+MODULE_DEVICE_TABLE (usb, usb_klsi_table);
-+
-+/****************************************************************
-+ * kaweth_driver
-+ ****************************************************************/
-+static struct usb_driver kaweth_driver = {
-+ .name = driver_name,
-+ .probe = kaweth_probe,
-+ .disconnect = kaweth_disconnect,
-+ .suspend = kaweth_suspend,
-+ .resume = kaweth_resume,
-+ .id_table = usb_klsi_table,
-+ .supports_autosuspend = 1,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+typedef __u8 eth_addr_t[6];
-+
-+/****************************************************************
-+ * usb_eth_dev
-+ ****************************************************************/
-+struct usb_eth_dev {
-+ char *name;
-+ __u16 vendor;
-+ __u16 device;
-+ void *pdata;
-+};
-+
-+/****************************************************************
-+ * kaweth_ethernet_configuration
-+ * Refer Table 8
-+ ****************************************************************/
-+struct kaweth_ethernet_configuration
-+{
-+ __u8 size;
-+ __u8 reserved1;
-+ __u8 reserved2;
-+ eth_addr_t hw_addr;
-+ __u32 statistics_mask;
-+ __le16 segment_size;
-+ __u16 max_multicast_filters;
-+ __u8 reserved3;
-+} __packed;
-+
-+/****************************************************************
-+ * kaweth_device
-+ ****************************************************************/
-+struct kaweth_device
-+{
-+ spinlock_t device_lock;
-+
-+ __u32 status;
-+ int end;
-+ int suspend_lowmem_rx;
-+ int suspend_lowmem_ctrl;
-+ int linkstate;
-+ int opened;
-+ struct delayed_work lowmem_work;
-+
-+ struct usb_device *dev;
-+ struct usb_interface *intf;
-+ struct net_device *net;
-+ wait_queue_head_t term_wait;
-+
-+ struct urb *rx_urb;
-+ struct urb *tx_urb;
-+ struct urb *irq_urb;
-+
-+ dma_addr_t intbufferhandle;
-+ __u8 *intbuffer;
-+ dma_addr_t rxbufferhandle;
-+ __u8 *rx_buf;
-+
-+
-+ struct sk_buff *tx_skb;
-+
-+ __u8 *firmware_buf;
-+ __u8 scratch[KAWETH_SCRATCH_SIZE];
-+ __u16 packet_filter_bitmap;
-+
-+ struct kaweth_ethernet_configuration configuration;
-+
-+ struct net_device_stats stats;
-+};
-+
-+/****************************************************************
-+ * kaweth_control
-+ ****************************************************************/
-+static int kaweth_control(struct kaweth_device *kaweth,
-+ unsigned int pipe,
-+ __u8 request,
-+ __u8 requesttype,
-+ __u16 value,
-+ __u16 index,
-+ void *data,
-+ __u16 size,
-+ int timeout)
-+{
-+ struct usb_ctrlrequest *dr;
-+ int retval;
-+
-+ netdev_dbg(kaweth->net, "kaweth_control()\n");
-+
-+ if(in_interrupt()) {
-+ netdev_dbg(kaweth->net, "in_interrupt()\n");
-+ return -EBUSY;
-+ }
-+
-+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
-+ if (!dr)
-+ return -ENOMEM;
-+
-+ dr->bRequestType = requesttype;
-+ dr->bRequest = request;
-+ dr->wValue = cpu_to_le16(value);
-+ dr->wIndex = cpu_to_le16(index);
-+ dr->wLength = cpu_to_le16(size);
-+
-+ retval = kaweth_internal_control_msg(kaweth->dev,
-+ pipe,
-+ dr,
-+ data,
-+ size,
-+ timeout);
-+
-+ kfree(dr);
-+ return retval;
-+}
-+
-+/****************************************************************
-+ * kaweth_read_configuration
-+ ****************************************************************/
-+static int kaweth_read_configuration(struct kaweth_device *kaweth)
-+{
-+ int retval;
-+
-+ netdev_dbg(kaweth->net, "Reading kaweth configuration\n");
-+
-+ retval = kaweth_control(kaweth,
-+ usb_rcvctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_GET_ETHERNET_DESC,
-+ USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
-+ 0,
-+ 0,
-+ (void *)&kaweth->configuration,
-+ sizeof(kaweth->configuration),
-+ KAWETH_CONTROL_TIMEOUT);
-+
-+ return retval;
-+}
-+
-+/****************************************************************
-+ * kaweth_set_urb_size
-+ ****************************************************************/
-+static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
-+{
-+ int retval;
-+
-+ netdev_dbg(kaweth->net, "Setting URB size to %d\n", (unsigned)urb_size);
-+
-+ retval = kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SET_URB_SIZE,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ urb_size,
-+ 0,
-+ (void *)&kaweth->scratch,
-+ 0,
-+ KAWETH_CONTROL_TIMEOUT);
-+
-+ return retval;
-+}
-+
-+/****************************************************************
-+ * kaweth_set_sofs_wait
-+ ****************************************************************/
-+static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
-+{
-+ int retval;
-+
-+ netdev_dbg(kaweth->net, "Set SOFS wait to %d\n", (unsigned)sofs_wait);
-+
-+ retval = kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SET_SOFS_WAIT,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ sofs_wait,
-+ 0,
-+ (void *)&kaweth->scratch,
-+ 0,
-+ KAWETH_CONTROL_TIMEOUT);
-+
-+ return retval;
-+}
-+
-+/****************************************************************
-+ * kaweth_set_receive_filter
-+ ****************************************************************/
-+static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
-+ __u16 receive_filter)
-+{
-+ int retval;
-+
-+ netdev_dbg(kaweth->net, "Set receive filter to %d\n",
-+ (unsigned)receive_filter);
-+
-+ retval = kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SET_PACKET_FILTER,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ receive_filter,
-+ 0,
-+ (void *)&kaweth->scratch,
-+ 0,
-+ KAWETH_CONTROL_TIMEOUT);
-+
-+ return retval;
-+}
-+
-+/****************************************************************
-+ * kaweth_download_firmware
-+ ****************************************************************/
-+static int kaweth_download_firmware(struct kaweth_device *kaweth,
-+ const char *fwname,
-+ __u8 interrupt,
-+ __u8 type)
-+{
-+ const struct firmware *fw;
-+ int data_len;
-+ int ret;
-+
-+ ret = request_firmware(&fw, fwname, &kaweth->dev->dev);
-+ if (ret) {
-+ dev_err(&kaweth->intf->dev, "Firmware request failed\n");
-+ return ret;
-+ }
-+
-+ if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
-+ dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n",
-+ fw->size);
-+ release_firmware(fw);
-+ return -ENOSPC;
-+ }
-+ data_len = fw->size;
-+ memcpy(kaweth->firmware_buf, fw->data, fw->size);
-+
-+ release_firmware(fw);
-+
-+ kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
-+ kaweth->firmware_buf[3] = data_len >> 8;
-+ kaweth->firmware_buf[4] = type;
-+ kaweth->firmware_buf[5] = interrupt;
-+
-+ netdev_dbg(kaweth->net, "High: %i, Low:%i\n", kaweth->firmware_buf[3],
-+ kaweth->firmware_buf[2]);
-+
-+ netdev_dbg(kaweth->net,
-+ "Downloading firmware at %p to kaweth device at %p\n",
-+ kaweth->firmware_buf, kaweth);
-+ netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len);
-+
-+ return kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SCAN,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ 0,
-+ 0,
-+ (void *)kaweth->firmware_buf,
-+ data_len,
-+ KAWETH_CONTROL_TIMEOUT);
-+}
-+
-+/****************************************************************
-+ * kaweth_trigger_firmware
-+ ****************************************************************/
-+static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
-+ __u8 interrupt)
-+{
-+ kaweth->firmware_buf[0] = 0xB6;
-+ kaweth->firmware_buf[1] = 0xC3;
-+ kaweth->firmware_buf[2] = 0x01;
-+ kaweth->firmware_buf[3] = 0x00;
-+ kaweth->firmware_buf[4] = 0x06;
-+ kaweth->firmware_buf[5] = interrupt;
-+ kaweth->firmware_buf[6] = 0x00;
-+ kaweth->firmware_buf[7] = 0x00;
-+
-+ netdev_dbg(kaweth->net, "Triggering firmware\n");
-+
-+ return kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SCAN,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ 0,
-+ 0,
-+ (void *)kaweth->firmware_buf,
-+ 8,
-+ KAWETH_CONTROL_TIMEOUT);
-+}
-+
-+/****************************************************************
-+ * kaweth_reset
-+ ****************************************************************/
-+static int kaweth_reset(struct kaweth_device *kaweth)
-+{
-+ int result;
-+
-+ netdev_dbg(kaweth->net, "kaweth_reset(%p)\n", kaweth);
-+ result = usb_reset_configuration(kaweth->dev);
-+ mdelay(10);
-+
-+ netdev_dbg(kaweth->net, "kaweth_reset() returns %d.\n", result);
-+
-+ return result;
-+}
-+
-+static void kaweth_usb_receive(struct urb *);
-+static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t);
-+
-+/****************************************************************
-+ int_callback
-+*****************************************************************/
-+
-+static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf)
-+{
-+ int status;
-+
-+ status = usb_submit_urb (kaweth->irq_urb, mf);
-+ if (unlikely(status == -ENOMEM)) {
-+ kaweth->suspend_lowmem_ctrl = 1;
-+ schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
-+ } else {
-+ kaweth->suspend_lowmem_ctrl = 0;
-+ }
-+
-+ if (status)
-+ dev_err(&kaweth->intf->dev,
-+ "can't resubmit intr, %s-%s, status %d\n",
-+ kaweth->dev->bus->bus_name,
-+ kaweth->dev->devpath, status);
-+}
-+
-+static void int_callback(struct urb *u)
-+{
-+ struct kaweth_device *kaweth = u->context;
-+ int act_state;
-+ int status = u->status;
-+
-+ switch (status) {
-+ case 0: /* success */
-+ break;
-+ case -ECONNRESET: /* unlink */
-+ case -ENOENT:
-+ case -ESHUTDOWN:
-+ return;
-+ /* -EPIPE: should clear the halt */
-+ default: /* error */
-+ goto resubmit;
-+ }
-+
-+ /* we check the link state to report changes */
-+ if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) {
-+ if (act_state)
-+ netif_carrier_on(kaweth->net);
-+ else
-+ netif_carrier_off(kaweth->net);
-+
-+ kaweth->linkstate = act_state;
-+ }
-+resubmit:
-+ kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC);
-+}
-+
-+static void kaweth_resubmit_tl(struct work_struct *work)
-+{
-+ struct kaweth_device *kaweth =
-+ container_of(work, struct kaweth_device, lowmem_work.work);
-+
-+ if (IS_BLOCKED(kaweth->status))
-+ return;
-+
-+ if (kaweth->suspend_lowmem_rx)
-+ kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
-+
-+ if (kaweth->suspend_lowmem_ctrl)
-+ kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
-+}
-+
-+
-+/****************************************************************
-+ * kaweth_resubmit_rx_urb
-+ ****************************************************************/
-+static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
-+ gfp_t mem_flags)
-+{
-+ int result;
-+
-+ usb_fill_bulk_urb(kaweth->rx_urb,
-+ kaweth->dev,
-+ usb_rcvbulkpipe(kaweth->dev, 1),
-+ kaweth->rx_buf,
-+ KAWETH_BUF_SIZE,
-+ kaweth_usb_receive,
-+ kaweth);
-+ kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-+ kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle;
-+
-+ if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) {
-+ if (result == -ENOMEM) {
-+ kaweth->suspend_lowmem_rx = 1;
-+ schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
-+ }
-+ dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n",
-+ result);
-+ } else {
-+ kaweth->suspend_lowmem_rx = 0;
-+ }
-+
-+ return result;
-+}
-+
-+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
-+
-+/****************************************************************
-+ * kaweth_usb_receive
-+ ****************************************************************/
-+static void kaweth_usb_receive(struct urb *urb)
-+{
-+ struct device *dev = &urb->dev->dev;
-+ struct kaweth_device *kaweth = urb->context;
-+ struct net_device *net = kaweth->net;
-+ int status = urb->status;
-+
-+ int count = urb->actual_length;
-+ int count2 = urb->transfer_buffer_length;
-+
-+ __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf);
-+
-+ struct sk_buff *skb;
-+
-+ if (unlikely(status == -EPIPE)) {
-+ kaweth->stats.rx_errors++;
-+ kaweth->end = 1;
-+ wake_up(&kaweth->term_wait);
-+ dev_dbg(dev, "Status was -EPIPE.\n");
-+ return;
-+ }
-+ if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) {
-+ /* we are killed - set a flag and wake the disconnect handler */
-+ kaweth->end = 1;
-+ wake_up(&kaweth->term_wait);
-+ dev_dbg(dev, "Status was -ECONNRESET or -ESHUTDOWN.\n");
-+ return;
-+ }
-+ if (unlikely(status == -EPROTO || status == -ETIME ||
-+ status == -EILSEQ)) {
-+ kaweth->stats.rx_errors++;
-+ dev_dbg(dev, "Status was -EPROTO, -ETIME, or -EILSEQ.\n");
-+ return;
-+ }
-+ if (unlikely(status == -EOVERFLOW)) {
-+ kaweth->stats.rx_errors++;
-+ dev_dbg(dev, "Status was -EOVERFLOW.\n");
-+ }
-+ spin_lock(&kaweth->device_lock);
-+ if (IS_BLOCKED(kaweth->status)) {
-+ spin_unlock(&kaweth->device_lock);
-+ return;
-+ }
-+ spin_unlock(&kaweth->device_lock);
-+
-+ if(status && status != -EREMOTEIO && count != 1) {
-+ dev_err(&kaweth->intf->dev,
-+ "%s RX status: %d count: %d packet_len: %d\n",
-+ net->name, status, count, (int)pkt_len);
-+ kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
-+ return;
-+ }
-+
-+ if(kaweth->net && (count > 2)) {
-+ if(pkt_len > (count - 2)) {
-+ dev_err(&kaweth->intf->dev,
-+ "Packet length too long for USB frame (pkt_len: %x, count: %x)\n",
-+ pkt_len, count);
-+ dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n",
-+ pkt_len & 2047);
-+ dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2);
-+ kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
-+ return;
-+ }
-+
-+ if(!(skb = dev_alloc_skb(pkt_len+2))) {
-+ kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
-+ return;
-+ }
-+
-+ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
-+
-+ skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len);
-+
-+ skb_put(skb, pkt_len);
-+
-+ skb->protocol = eth_type_trans(skb, net);
-+
-+ netif_rx(skb);
-+
-+ kaweth->stats.rx_packets++;
-+ kaweth->stats.rx_bytes += pkt_len;
-+ }
-+
-+ kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
-+}
-+
-+/****************************************************************
-+ * kaweth_open
-+ ****************************************************************/
-+static int kaweth_open(struct net_device *net)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(net);
-+ int res;
-+
-+ netdev_dbg(kaweth->net, "Opening network device.\n");
-+
-+ res = usb_autopm_get_interface(kaweth->intf);
-+ if (res) {
-+ dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n");
-+ return -EIO;
-+ }
-+ res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
-+ if (res)
-+ goto err_out;
-+
-+ usb_fill_int_urb(
-+ kaweth->irq_urb,
-+ kaweth->dev,
-+ usb_rcvintpipe(kaweth->dev, 3),
-+ kaweth->intbuffer,
-+ INTBUFFERSIZE,
-+ int_callback,
-+ kaweth,
-+ 250); /* overriding the descriptor */
-+ kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle;
-+ kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-+
-+ res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
-+ if (res) {
-+ usb_kill_urb(kaweth->rx_urb);
-+ goto err_out;
-+ }
-+ kaweth->opened = 1;
-+
-+ netif_start_queue(net);
-+
-+ kaweth_async_set_rx_mode(kaweth);
-+ return 0;
-+
-+err_out:
-+ usb_autopm_put_interface(kaweth->intf);
-+ return -EIO;
-+}
-+
-+/****************************************************************
-+ * kaweth_kill_urbs
-+ ****************************************************************/
-+static void kaweth_kill_urbs(struct kaweth_device *kaweth)
-+{
-+ usb_kill_urb(kaweth->irq_urb);
-+ usb_kill_urb(kaweth->rx_urb);
-+ usb_kill_urb(kaweth->tx_urb);
-+
-+ cancel_delayed_work_sync(&kaweth->lowmem_work);
-+
-+ /* a scheduled work may have resubmitted,
-+ we hit them again */
-+ usb_kill_urb(kaweth->irq_urb);
-+ usb_kill_urb(kaweth->rx_urb);
-+}
-+
-+/****************************************************************
-+ * kaweth_close
-+ ****************************************************************/
-+static int kaweth_close(struct net_device *net)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(net);
-+
-+ netif_stop_queue(net);
-+ kaweth->opened = 0;
-+
-+ kaweth->status |= KAWETH_STATUS_CLOSING;
-+
-+ kaweth_kill_urbs(kaweth);
-+
-+ kaweth->status &= ~KAWETH_STATUS_CLOSING;
-+
-+ usb_autopm_put_interface(kaweth->intf);
-+
-+ return 0;
-+}
-+
-+static u32 kaweth_get_link(struct net_device *dev)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(dev);
-+
-+ return kaweth->linkstate;
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_link = kaweth_get_link
-+};
-+
-+/****************************************************************
-+ * kaweth_usb_transmit_complete
-+ ****************************************************************/
-+static void kaweth_usb_transmit_complete(struct urb *urb)
-+{
-+ struct kaweth_device *kaweth = urb->context;
-+ struct sk_buff *skb = kaweth->tx_skb;
-+ int status = urb->status;
-+
-+ if (unlikely(status != 0))
-+ if (status != -ENOENT)
-+ dev_dbg(&urb->dev->dev, "%s: TX status %d.\n",
-+ kaweth->net->name, status);
-+
-+ netif_wake_queue(kaweth->net);
-+ dev_kfree_skb_irq(skb);
-+}
-+
-+/****************************************************************
-+ * kaweth_start_xmit
-+ ****************************************************************/
-+static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb,
-+ struct net_device *net)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(net);
-+ __le16 *private_header;
-+
-+ int res;
-+
-+ spin_lock_irq(&kaweth->device_lock);
-+
-+ kaweth_async_set_rx_mode(kaweth);
-+ netif_stop_queue(net);
-+ if (IS_BLOCKED(kaweth->status)) {
-+ goto skip;
-+ }
-+
-+ /* We now decide whether we can put our special header into the sk_buff */
-+ if (skb_cloned(skb) || skb_headroom(skb) < 2) {
-+ /* no such luck - we make our own */
-+ struct sk_buff *copied_skb;
-+ copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
-+ dev_kfree_skb_irq(skb);
-+ skb = copied_skb;
-+ if (!copied_skb) {
-+ kaweth->stats.tx_errors++;
-+ netif_start_queue(net);
-+ spin_unlock_irq(&kaweth->device_lock);
-+ return NETDEV_TX_OK;
-+ }
-+ }
-+
-+ private_header = (__le16 *)__skb_push(skb, 2);
-+ *private_header = cpu_to_le16(skb->len-2);
-+ kaweth->tx_skb = skb;
-+
-+ usb_fill_bulk_urb(kaweth->tx_urb,
-+ kaweth->dev,
-+ usb_sndbulkpipe(kaweth->dev, 2),
-+ private_header,
-+ skb->len,
-+ kaweth_usb_transmit_complete,
-+ kaweth);
-+ kaweth->end = 0;
-+
-+ if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
-+ {
-+ dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res);
-+skip:
-+ kaweth->stats.tx_errors++;
-+
-+ netif_start_queue(net);
-+ dev_kfree_skb_irq(skb);
-+ }
-+ else
-+ {
-+ kaweth->stats.tx_packets++;
-+ kaweth->stats.tx_bytes += skb->len;
-+ }
-+
-+ spin_unlock_irq(&kaweth->device_lock);
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+/****************************************************************
-+ * kaweth_set_rx_mode
-+ ****************************************************************/
-+static void kaweth_set_rx_mode(struct net_device *net)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(net);
-+
-+ __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
-+ KAWETH_PACKET_FILTER_BROADCAST |
-+ KAWETH_PACKET_FILTER_MULTICAST;
-+
-+ netdev_dbg(net, "Setting Rx mode to %d\n", packet_filter_bitmap);
-+
-+ netif_stop_queue(net);
-+
-+ if (net->flags & IFF_PROMISC) {
-+ packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
-+ }
-+ else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
-+ packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
-+ }
-+
-+ kaweth->packet_filter_bitmap = packet_filter_bitmap;
-+ netif_wake_queue(net);
-+}
-+
-+/****************************************************************
-+ * kaweth_async_set_rx_mode
-+ ****************************************************************/
-+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
-+{
-+ int result;
-+ __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
-+
-+ kaweth->packet_filter_bitmap = 0;
-+ if (packet_filter_bitmap == 0)
-+ return;
-+
-+ if (in_interrupt())
-+ return;
-+
-+ result = kaweth_control(kaweth,
-+ usb_sndctrlpipe(kaweth->dev, 0),
-+ KAWETH_COMMAND_SET_PACKET_FILTER,
-+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-+ packet_filter_bitmap,
-+ 0,
-+ (void *)&kaweth->scratch,
-+ 0,
-+ KAWETH_CONTROL_TIMEOUT);
-+
-+ if(result < 0) {
-+ dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
-+ result);
-+ }
-+ else {
-+ netdev_dbg(kaweth->net, "Set Rx mode to %d\n",
-+ packet_filter_bitmap);
-+ }
-+}
-+
-+/****************************************************************
-+ * kaweth_netdev_stats
-+ ****************************************************************/
-+static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(dev);
-+ return &kaweth->stats;
-+}
-+
-+/****************************************************************
-+ * kaweth_tx_timeout
-+ ****************************************************************/
-+static void kaweth_tx_timeout(struct net_device *net)
-+{
-+ struct kaweth_device *kaweth = netdev_priv(net);
-+
-+ dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name);
-+ kaweth->stats.tx_errors++;
-+ net->trans_start = jiffies;
-+
-+ usb_unlink_urb(kaweth->tx_urb);
-+}
-+
-+/****************************************************************
-+ * kaweth_suspend
-+ ****************************************************************/
-+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
-+ unsigned long flags;
-+
-+ dev_dbg(&intf->dev, "Suspending device\n");
-+ spin_lock_irqsave(&kaweth->device_lock, flags);
-+ kaweth->status |= KAWETH_STATUS_SUSPENDING;
-+ spin_unlock_irqrestore(&kaweth->device_lock, flags);
-+
-+ kaweth_kill_urbs(kaweth);
-+ return 0;
-+}
-+
-+/****************************************************************
-+ * kaweth_resume
-+ ****************************************************************/
-+static int kaweth_resume(struct usb_interface *intf)
-+{
-+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
-+ unsigned long flags;
-+
-+ dev_dbg(&intf->dev, "Resuming device\n");
-+ spin_lock_irqsave(&kaweth->device_lock, flags);
-+ kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
-+ spin_unlock_irqrestore(&kaweth->device_lock, flags);
-+
-+ if (!kaweth->opened)
-+ return 0;
-+ kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
-+ kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
-+
-+ return 0;
-+}
-+
-+/****************************************************************
-+ * kaweth_probe
-+ ****************************************************************/
-+
-+
-+static const struct net_device_ops kaweth_netdev_ops = {
-+ .ndo_open = kaweth_open,
-+ .ndo_stop = kaweth_close,
-+ .ndo_start_xmit = kaweth_start_xmit,
-+ .ndo_tx_timeout = kaweth_tx_timeout,
-+ .ndo_set_rx_mode = kaweth_set_rx_mode,
-+ .ndo_get_stats = kaweth_netdev_stats,
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+};
-+
-+static int kaweth_probe(
-+ struct usb_interface *intf,
-+ const struct usb_device_id *id /* from id_table */
-+ )
-+{
-+ struct device *dev = &intf->dev;
-+ struct usb_device *udev = interface_to_usbdev(intf);
-+ struct kaweth_device *kaweth;
-+ struct net_device *netdev;
-+ const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-+ int result = 0;
-+
-+ dev_dbg(dev,
-+ "Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n",
-+ udev->devnum, le16_to_cpu(udev->descriptor.idVendor),
-+ le16_to_cpu(udev->descriptor.idProduct),
-+ le16_to_cpu(udev->descriptor.bcdDevice));
-+
-+ dev_dbg(dev, "Device at %p\n", udev);
-+
-+ dev_dbg(dev, "Descriptor length: %x type: %x\n",
-+ (int)udev->descriptor.bLength,
-+ (int)udev->descriptor.bDescriptorType);
-+
-+ netdev = alloc_etherdev(sizeof(*kaweth));
-+ if (!netdev)
-+ return -ENOMEM;
-+
-+ kaweth = netdev_priv(netdev);
-+ kaweth->dev = udev;
-+ kaweth->net = netdev;
-+
-+ spin_lock_init(&kaweth->device_lock);
-+ init_waitqueue_head(&kaweth->term_wait);
-+
-+ dev_dbg(dev, "Resetting.\n");
-+
-+ kaweth_reset(kaweth);
-+
-+ /*
-+ * If high byte of bcdDevice is nonzero, firmware is already
-+ * downloaded. Don't try to do it again, or we'll hang the device.
-+ */
-+
-+ if (le16_to_cpu(udev->descriptor.bcdDevice) >> 8) {
-+ dev_info(dev, "Firmware present in device.\n");
-+ } else {
-+ /* Download the firmware */
-+ dev_info(dev, "Downloading firmware...\n");
-+ kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
-+ if ((result = kaweth_download_firmware(kaweth,
-+ "kaweth/new_code.bin",
-+ 100,
-+ 2)) < 0) {
-+ dev_err(dev, "Error downloading firmware (%d)\n",
-+ result);
-+ goto err_fw;
-+ }
-+
-+ if ((result = kaweth_download_firmware(kaweth,
-+ "kaweth/new_code_fix.bin",
-+ 100,
-+ 3)) < 0) {
-+ dev_err(dev, "Error downloading firmware fix (%d)\n",
-+ result);
-+ goto err_fw;
-+ }
-+
-+ if ((result = kaweth_download_firmware(kaweth,
-+ "kaweth/trigger_code.bin",
-+ 126,
-+ 2)) < 0) {
-+ dev_err(dev, "Error downloading trigger code (%d)\n",
-+ result);
-+ goto err_fw;
-+
-+ }
-+
-+ if ((result = kaweth_download_firmware(kaweth,
-+ "kaweth/trigger_code_fix.bin",
-+ 126,
-+ 3)) < 0) {
-+ dev_err(dev, "Error downloading trigger code fix (%d)\n", result);
-+ goto err_fw;
-+ }
-+
-+
-+ if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
-+ dev_err(dev, "Error triggering firmware (%d)\n", result);
-+ goto err_fw;
-+ }
-+
-+ /* Device will now disappear for a moment... */
-+ dev_info(dev, "Firmware loaded. I'll be back...\n");
-+err_fw:
-+ free_page((unsigned long)kaweth->firmware_buf);
-+ free_netdev(netdev);
-+ return -EIO;
-+ }
-+
-+ result = kaweth_read_configuration(kaweth);
-+
-+ if(result < 0) {
-+ dev_err(dev, "Error reading configuration (%d), no net device created\n", result);
-+ goto err_free_netdev;
-+ }
-+
-+ dev_info(dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask);
-+ dev_info(dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
-+ dev_info(dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size));
-+ dev_info(dev, "Read MAC address %pM\n", kaweth->configuration.hw_addr);
-+
-+ if(!memcmp(&kaweth->configuration.hw_addr,
-+ &bcast_addr,
-+ sizeof(bcast_addr))) {
-+ dev_err(dev, "Firmware not functioning properly, no net device created\n");
-+ goto err_free_netdev;
-+ }
-+
-+ if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
-+ dev_dbg(dev, "Error setting URB size\n");
-+ goto err_free_netdev;
-+ }
-+
-+ if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
-+ dev_err(dev, "Error setting SOFS wait\n");
-+ goto err_free_netdev;
-+ }
-+
-+ result = kaweth_set_receive_filter(kaweth,
-+ KAWETH_PACKET_FILTER_DIRECTED |
-+ KAWETH_PACKET_FILTER_BROADCAST |
-+ KAWETH_PACKET_FILTER_MULTICAST);
-+
-+ if(result < 0) {
-+ dev_err(dev, "Error setting receive filter\n");
-+ goto err_free_netdev;
-+ }
-+
-+ dev_dbg(dev, "Initializing net device.\n");
-+
-+ kaweth->intf = intf;
-+
-+ kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!kaweth->tx_urb)
-+ goto err_free_netdev;
-+ kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!kaweth->rx_urb)
-+ goto err_only_tx;
-+ kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!kaweth->irq_urb)
-+ goto err_tx_and_rx;
-+
-+ kaweth->intbuffer = usb_alloc_coherent( kaweth->dev,
-+ INTBUFFERSIZE,
-+ GFP_KERNEL,
-+ &kaweth->intbufferhandle);
-+ if (!kaweth->intbuffer)
-+ goto err_tx_and_rx_and_irq;
-+ kaweth->rx_buf = usb_alloc_coherent( kaweth->dev,
-+ KAWETH_BUF_SIZE,
-+ GFP_KERNEL,
-+ &kaweth->rxbufferhandle);
-+ if (!kaweth->rx_buf)
-+ goto err_all_but_rxbuf;
-+
-+ memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr));
-+ memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr,
-+ sizeof(kaweth->configuration.hw_addr));
-+
-+ netdev->netdev_ops = &kaweth_netdev_ops;
-+ netdev->watchdog_timeo = KAWETH_TX_TIMEOUT;
-+ netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size);
-+ netdev->ethtool_ops = &ops;
-+
-+ /* kaweth is zeroed as part of alloc_netdev */
-+ INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
-+ usb_set_intfdata(intf, kaweth);
-+
-+#if 0
-+// dma_supported() is deeply broken on almost all architectures
-+ if (dma_supported (dev, 0xffffffffffffffffULL))
-+ kaweth->net->features |= NETIF_F_HIGHDMA;
-+#endif
-+
-+ SET_NETDEV_DEV(netdev, dev);
-+ if (register_netdev(netdev) != 0) {
-+ dev_err(dev, "Error registering netdev.\n");
-+ goto err_intfdata;
-+ }
-+
-+ dev_info(dev, "kaweth interface created at %s\n",
-+ kaweth->net->name);
-+
-+ dev_dbg(dev, "Kaweth probe returning.\n");
-+
-+ return 0;
-+
-+err_intfdata:
-+ usb_set_intfdata(intf, NULL);
-+ usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
-+err_all_but_rxbuf:
-+ usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
-+err_tx_and_rx_and_irq:
-+ usb_free_urb(kaweth->irq_urb);
-+err_tx_and_rx:
-+ usb_free_urb(kaweth->rx_urb);
-+err_only_tx:
-+ usb_free_urb(kaweth->tx_urb);
-+err_free_netdev:
-+ free_netdev(netdev);
-+
-+ return -EIO;
-+}
-+
-+/****************************************************************
-+ * kaweth_disconnect
-+ ****************************************************************/
-+static void kaweth_disconnect(struct usb_interface *intf)
-+{
-+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
-+ struct net_device *netdev;
-+
-+ dev_info(&intf->dev, "Unregistering\n");
-+
-+ usb_set_intfdata(intf, NULL);
-+ if (!kaweth) {
-+ dev_warn(&intf->dev, "unregistering non-existent device\n");
-+ return;
-+ }
-+ netdev = kaweth->net;
-+
-+ netdev_dbg(kaweth->net, "Unregistering net device\n");
-+ unregister_netdev(netdev);
-+
-+ usb_free_urb(kaweth->rx_urb);
-+ usb_free_urb(kaweth->tx_urb);
-+ usb_free_urb(kaweth->irq_urb);
-+
-+ usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle);
-+ usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle);
-+
-+ free_netdev(netdev);
-+}
-+
-+
-+// FIXME this completion stuff is a modified clone of
-+// an OLD version of some stuff in usb.c ...
-+struct usb_api_data {
-+ wait_queue_head_t wqh;
-+ int done;
-+};
-+
-+/*-------------------------------------------------------------------*
-+ * completion handler for compatibility wrappers (sync control/bulk) *
-+ *-------------------------------------------------------------------*/
-+static void usb_api_blocking_completion(struct urb *urb)
-+{
-+ struct usb_api_data *awd = (struct usb_api_data *)urb->context;
-+
-+ awd->done=1;
-+ wake_up(&awd->wqh);
-+}
-+
-+/*-------------------------------------------------------------------*
-+ * COMPATIBILITY STUFF *
-+ *-------------------------------------------------------------------*/
-+
-+// Starts urb and waits for completion or timeout
-+static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
-+{
-+ struct usb_api_data awd;
-+ int status;
-+
-+ init_waitqueue_head(&awd.wqh);
-+ awd.done = 0;
-+
-+ urb->context = &awd;
-+ status = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (status) {
-+ // something went wrong
-+ usb_free_urb(urb);
-+ return status;
-+ }
-+
-+ if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
-+ // timeout
-+ dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n");
-+ usb_kill_urb(urb); // remove urb safely
-+ status = -ETIMEDOUT;
-+ }
-+ else {
-+ status = urb->status;
-+ }
-+
-+ if (actual_length) {
-+ *actual_length = urb->actual_length;
-+ }
-+
-+ usb_free_urb(urb);
-+ return status;
-+}
-+
-+/*-------------------------------------------------------------------*/
-+// returns status (negative) or length (positive)
-+static int kaweth_internal_control_msg(struct usb_device *usb_dev,
-+ unsigned int pipe,
-+ struct usb_ctrlrequest *cmd, void *data,
-+ int len, int timeout)
-+{
-+ struct urb *urb;
-+ int retv;
-+ int length = 0; /* shut up GCC */
-+
-+ urb = usb_alloc_urb(0, GFP_ATOMIC);
-+ if (!urb)
-+ return -ENOMEM;
-+
-+ usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data,
-+ len, usb_api_blocking_completion, NULL);
-+
-+ retv = usb_start_wait_urb(urb, timeout, &length);
-+ if (retv < 0) {
-+ return retv;
-+ }
-+ else {
-+ return length;
-+ }
-+}
-+
-+module_usb_driver(kaweth_driver);
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/Kconfig backports-4.2.6-1/drivers/net/usb/Kconfig
---- backports-4.2.6-1.org/drivers/net/usb/Kconfig 2015-11-15 22:19:40.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/Kconfig 2016-06-28 14:35:17.991973886 +0200
-@@ -13,7 +13,6 @@
- if USB_NET_DRIVERS
-
- config USB_CATC
-- depends on n
- tristate "USB CATC NetMate-based Ethernet device support"
- depends on m
- depends on CRC32
-@@ -34,7 +33,6 @@
- module will be called catc.
-
- config USB_KAWETH
-- depends on n
- tristate "USB KLSI KL5USB101-based ethernet device support"
- depends on m
- ---help---
-@@ -75,7 +73,6 @@
- module will be called kaweth.
-
- config USB_PEGASUS
-- depends on n
- tristate "USB Pegasus/Pegasus-II based ethernet device support"
- depends on m
- select BPAUTO_MII
-@@ -92,7 +89,6 @@
- module will be called pegasus.
-
- config USB_RTL8150
-- depends on n
- tristate "USB RTL8150 based ethernet device support"
- depends on m
- select BPAUTO_MII
-@@ -105,7 +101,6 @@
- module will be called rtl8150.
-
- config USB_RTL8152
-- depends on n
- tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
- depends on m
- select BPAUTO_MII
-@@ -153,7 +148,6 @@
- module will be called usbnet.
-
- config USB_NET_AX8817X
-- depends on n
- tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
- depends on m
- depends on USB_USBNET
-@@ -184,7 +178,6 @@
- what other networking devices you have in use.
-
- config USB_NET_AX88179_178A
-- depends on n
- tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet"
- depends on m
- depends on USB_USBNET
-@@ -233,7 +226,6 @@
- name is used instead.
-
- config USB_NET_CDC_EEM
-- depends on n
- tristate "CDC EEM support"
- depends on m
- depends on USB_USBNET
-@@ -269,7 +261,6 @@
- * Ericsson F5521gw Mobile Broadband Module
-
- config USB_NET_HUAWEI_CDC_NCM
-- depends on n
- tristate "Huawei NCM embedded AT channel support"
- depends on m
- depends on USB_USBNET
-@@ -305,7 +296,6 @@
- module will be called cdc_mbim.
-
- config USB_NET_DM9601
-- depends on n
- tristate "Davicom DM96xx based USB 10/100 ethernet devices"
- depends on m
- depends on USB_USBNET
-@@ -315,7 +305,6 @@
- based USB 10/100 Ethernet adapters.
-
- config USB_NET_SR9700
-- depends on n
- tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
- depends on m
- depends on USB_USBNET
-@@ -325,7 +314,6 @@
- 10/100 Ethernet adapters.
-
- config USB_NET_SR9800
-- depends on n
- tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
- depends on m
- depends on USB_USBNET
-@@ -342,7 +330,6 @@
- module will be called sr9800.
-
- config USB_NET_SMSC75XX
-- depends on n
- tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
- depends on m
- depends on USB_USBNET
-@@ -354,7 +341,6 @@
- Gigabit Ethernet adapters.
-
- config USB_NET_SMSC95XX
-- depends on n
- tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"
- depends on m
- depends on USB_USBNET
-@@ -366,7 +352,6 @@
- 10/100 Ethernet adapters.
-
- config USB_NET_GL620A
-- depends on n
- tristate "GeneSys GL620USB-A based cables"
- depends on m
- depends on USB_USBNET
-@@ -377,7 +362,6 @@
- Note that the half-duplex "GL620USB" is not supported.
-
- config USB_NET_NET1080
-- depends on n
- tristate "NetChip 1080 based cables (Laplink, ...)"
- depends on m
- default y
-@@ -388,7 +372,6 @@
- optionally with LEDs that indicate traffic
-
- config USB_NET_PLUSB
-- depends on n
- tristate "Prolific PL-2301/2302/25A1 based cables"
- depends on m
- # if the handshake/init/reset problems, from original 'plusb',
-@@ -399,7 +382,6 @@
- with one of these chips.
-
- config USB_NET_MCS7830
-- depends on n
- tristate "MosChip MCS7830 based Ethernet adapters"
- depends on m
- depends on USB_USBNET
-@@ -425,7 +407,6 @@
- (and for) Microsoft; it isn't an "Open" ecosystem or market.
-
- config USB_NET_CDC_SUBSET
-- depends on n
- tristate "Simple USB Network Links (CDC Ethernet subset)"
- depends on m
- depends on USB_USBNET
-@@ -497,7 +478,6 @@
- with one of these chips.
-
- config USB_NET_ZAURUS
-- depends on n
- tristate "Sharp Zaurus (stock ROMs) and compatible"
- depends on m
- depends on USB_USBNET
-@@ -517,7 +497,6 @@
- some cases CDC MDLM) protocol, not "g_ether".
-
- config USB_NET_CX82310_ETH
-- depends on n
- tristate "Conexant CX82310 USB ethernet port"
- depends on m
- depends on USB_USBNET
-@@ -527,7 +506,6 @@
- it will not work with ADSL modems (use cxacru driver instead).
-
- config USB_NET_KALMIA
-- depends on n
- tristate "Samsung Kalmia based LTE USB modem"
- depends on m
- depends on USB_USBNET
-@@ -562,7 +540,6 @@
- module will be called qmi_wwan.
-
- config USB_HSO
-- depends on n
- tristate "Option USB High Speed Mobile Devices"
- depends on m
- depends on USB && RFKILL && TTY
-@@ -575,7 +552,6 @@
- module will be called hso.
-
- config USB_NET_INT51X1
-- depends on n
- tristate "Intellon PLC based usb adapter"
- depends on m
- depends on USB_USBNET
-@@ -585,7 +561,6 @@
- INT51x1/INT5200 chip, like the "devolo dLan duo".
-
- config USB_CDC_PHONET
-- depends on n
- tristate "CDC Phonet support"
- depends on m
- depends on PHONET
-@@ -595,7 +570,6 @@
- "PC suite" USB profile.
-
- config USB_IPHETH
-- depends on n
- tristate "Apple iPhone USB Ethernet driver"
- depends on m
- default n
-@@ -619,11 +593,10 @@
- module will be called sierra_net.
-
- config USB_VL600
-- depends on n
- tristate "LG VL600 modem dongle"
- depends on m
- depends on USB_NET_CDCETHER && TTY
-- select USB_ACM
-+# depends on USB_ACM
- help
- Select this if you want to use an LG Electronics 4G/LTE usb modem
- called VL600. This driver only handles the ethernet
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/Kconfig.orig backports-4.2.6-1/drivers/net/usb/Kconfig.orig
---- backports-4.2.6-1.org/drivers/net/usb/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/Kconfig.orig 2016-06-28 14:35:17.991973886 +0200
-@@ -0,0 +1,638 @@
-+#
-+# USB Network devices configuration
-+#
-+comment "Host-side USB support is needed for USB Network Adapter support"
-+ depends on !USB && NET
-+
-+menuconfig USB_NET_DRIVERS
-+ tristate "USB Network Adapters"
-+ depends on m
-+ default USB if USB
-+ depends on USB && NET
-+
-+if USB_NET_DRIVERS
-+
-+config USB_CATC
-+ depends on n
-+ tristate "USB CATC NetMate-based Ethernet device support"
-+ depends on m
-+ depends on CRC32
-+ ---help---
-+ Say Y if you want to use one of the following 10Mbps USB Ethernet
-+ device based on the EL1210A chip. Supported devices are:
-+ Belkin F5U011
-+ Belkin F5U111
-+ CATC NetMate
-+ CATC NetMate II
-+ smartBridges smartNIC
-+
-+ This driver makes the adapter appear as a normal Ethernet interface,
-+ typically on eth0, if it is the only ethernet device, or perhaps on
-+ eth1, if you have a PCI or ISA ethernet card installed.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called catc.
-+
-+config USB_KAWETH
-+ depends on n
-+ tristate "USB KLSI KL5USB101-based ethernet device support"
-+ depends on m
-+ ---help---
-+ Say Y here if you want to use one of the following 10Mbps only
-+ USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
-+ 3Com 3C19250
-+ ADS USB-10BT
-+ ATEN USB Ethernet
-+ ASANTE USB To Ethernet Adapter
-+ AOX Endpoints USB Ethernet
-+ Correga K.K.
-+ D-Link DSB-650C and DU-E10
-+ Entrega / Portgear E45
-+ I-O DATA USB-ET/T
-+ Jaton USB Ethernet Device Adapter
-+ Kingston Technology USB Ethernet Adapter
-+ Linksys USB10T
-+ Mobility USB-Ethernet Adapter
-+ NetGear EA-101
-+ Peracom Enet and Enet2
-+ Portsmith Express Ethernet Adapter
-+ Shark Pocket Adapter
-+ SMC 2202USB
-+ Sony Vaio port extender
-+
-+ This driver is likely to work with most 10Mbps only USB Ethernet
-+ adapters, including some "no brand" devices. It does NOT work on
-+ SmartBridges smartNIC or on Belkin F5U111 devices - you should use
-+ the CATC NetMate driver for those. If you are not sure which one
-+ you need, select both, and the correct one should be selected for
-+ you.
-+
-+ This driver makes the adapter appear as a normal Ethernet interface,
-+ typically on eth0, if it is the only ethernet device, or perhaps on
-+ eth1, if you have a PCI or ISA ethernet card installed.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called kaweth.
-+
-+config USB_PEGASUS
-+ depends on n
-+ tristate "USB Pegasus/Pegasus-II based ethernet device support"
-+ depends on m
-+ select BPAUTO_MII
-+ ---help---
-+ Say Y here if you know you have Pegasus or Pegasus-II based adapter.
-+ If in doubt then look at <file:drivers/net/usb/pegasus.h> for the
-+ complete list of supported devices.
-+
-+ If your particular adapter is not in the list and you are _sure_ it
-+ is Pegasus or Pegasus II based then send me
-+ <petkan@users.sourceforge.net> vendor and device IDs.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called pegasus.
-+
-+config USB_RTL8150
-+ depends on n
-+ tristate "USB RTL8150 based ethernet device support"
-+ depends on m
-+ select BPAUTO_MII
-+ help
-+ Say Y here if you have RTL8150 based usb-ethernet adapter.
-+ Send me <petkan@users.sourceforge.net> any comments you may have.
-+ You can also check for updates at <http://pegasus2.sourceforge.net/>.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called rtl8150.
-+
-+config USB_RTL8152
-+ depends on n
-+ tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
-+ depends on m
-+ select BPAUTO_MII
-+ help
-+ This option adds support for Realtek RTL8152 based USB 2.0
-+ 10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000
-+ Ethernet adapters.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called r8152.
-+
-+config USB_USBNET
-+ tristate "Multi-purpose USB Networking Framework"
-+ depends on m
-+ select BPAUTO_MII
-+ ---help---
-+ This driver supports several kinds of network links over USB,
-+ with "minidrivers" built around a common network driver core
-+ that supports deep queues for efficient transfers. (This gives
-+ better performance with small packets and at high speeds).
-+
-+ The USB host runs "usbnet", and the other end of the link might be:
-+
-+ - Another USB host, when using USB "network" or "data transfer"
-+ cables. These are often used to network laptops to PCs, like
-+ "Laplink" parallel cables or some motherboards. These rely
-+ on specialized chips from many suppliers.
-+
-+ - An intelligent USB gadget, perhaps embedding a Linux system.
-+ These include PDAs running Linux (iPaq, Yopy, Zaurus, and
-+ others), and devices that interoperate using the standard
-+ CDC-Ethernet specification (including many cable modems).
-+
-+ - Network adapter hardware (like those for 10/100 Ethernet) which
-+ uses this driver framework.
-+
-+ The link will appear with a name like "usb0", when the link is
-+ a two-node link, or "eth0" for most CDC-Ethernet devices. Those
-+ two-node links are most easily managed with Ethernet Bridging
-+ (CONFIG_BRIDGE) instead of routing.
-+
-+ For more information see <http://www.linux-usb.org/usbnet/>.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called usbnet.
-+
-+config USB_NET_AX8817X
-+ depends on n
-+ tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on CRC32
-+ depends on PHYLIB
-+ default y
-+ help
-+ This option adds support for ASIX AX88xxx based USB 2.0
-+ 10/100 Ethernet adapters.
-+
-+ This driver should work with at least the following devices:
-+ * Aten UC210T
-+ * ASIX AX88172
-+ * Billionton Systems, USB2AR
-+ * Buffalo LUA-U2-KTX
-+ * Corega FEther USB2-TX
-+ * D-Link DUB-E100
-+ * Hawking UF200
-+ * Linksys USB200M
-+ * Netgear FA120
-+ * Sitecom LN-029
-+ * Sitecom LN-028
-+ * Intellinet USB 2.0 Ethernet
-+ * ST Lab USB 2.0 Ethernet
-+ * TrendNet TU2-ET100
-+
-+ This driver creates an interface named "ethX", where X depends on
-+ what other networking devices you have in use.
-+
-+config USB_NET_AX88179_178A
-+ depends on n
-+ tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on CRC32
-+ depends on PHYLIB
-+ default y
-+ help
-+ This option adds support for ASIX AX88179 based USB 3.0/2.0
-+ to Gigabit Ethernet adapters.
-+
-+ This driver should work with at least the following devices:
-+ * ASIX AX88179
-+ * ASIX AX88178A
-+ * Sitcomm LN-032
-+
-+ This driver creates an interface named "ethX", where X depends on
-+ what other networking devices you have in use.
-+
-+config USB_NET_CDCETHER
-+ tristate "CDC Ethernet support (smart devices such as cable modems)"
-+ depends on m
-+ depends on USB_USBNET
-+ default y
-+ help
-+ This option supports devices conforming to the Communication Device
-+ Class (CDC) Ethernet Control Model, a specification that's easy to
-+ implement in device firmware. The CDC specifications are available
-+ from <http://www.usb.org/>.
-+
-+ CDC Ethernet is an implementation option for DOCSIS cable modems
-+ that support USB connectivity, used for non-Microsoft USB hosts.
-+ The Linux-USB CDC Ethernet Gadget driver is an open implementation.
-+ This driver should work with at least the following devices:
-+
-+ * Dell Wireless 5530 HSPA
-+ * Ericsson PipeRider (all variants)
-+ * Ericsson Mobile Broadband Module (all variants)
-+ * Motorola (DM100 and SB4100)
-+ * Broadcom Cable Modem (reference design)
-+ * Toshiba (PCX1100U and F3507g/F3607gw)
-+ * ...
-+
-+ This driver creates an interface named "ethX", where X depends on
-+ what other networking devices you have in use. However, if the
-+ IEEE 802 "local assignment" bit is set in the address, a "usbX"
-+ name is used instead.
-+
-+config USB_NET_CDC_EEM
-+ depends on n
-+ tristate "CDC EEM support"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ This option supports devices conforming to the Communication Device
-+ Class (CDC) Ethernet Emulation Model, a specification that's easy to
-+ implement in device firmware. The CDC EEM specifications are available
-+ from <http://www.usb.org/>.
-+
-+ This driver creates an interface named "ethX", where X depends on
-+ what other networking devices you have in use. However, if the
-+ IEEE 802 "local assignment" bit is set in the address, a "usbX"
-+ name is used instead.
-+
-+config USB_NET_CDC_NCM
-+ tristate "CDC NCM support"
-+ depends on m
-+ depends on USB_USBNET
-+ default y
-+ help
-+ This driver provides support for CDC NCM (Network Control Model
-+ Device USB Class Specification). The CDC NCM specification is
-+ available from <http://www.usb.org/>.
-+
-+ Say "y" to link the driver statically, or "m" to build a
-+ dynamically linked module.
-+
-+ This driver should work with at least the following devices:
-+ * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design)
-+ * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design)
-+ * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design)
-+ * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design)
-+ * Ericsson F5521gw Mobile Broadband Module
-+
-+config USB_NET_HUAWEI_CDC_NCM
-+ depends on n
-+ tristate "Huawei NCM embedded AT channel support"
-+ depends on m
-+ depends on USB_USBNET
-+ select USB_WDM
-+ select USB_NET_CDC_NCM
-+ help
-+ This driver supports huawei-style NCM devices, that use NCM as a
-+ transport for other protocols, usually an embedded AT channel.
-+ Good examples are:
-+ * Huawei E3131
-+ * Huawei E3251
-+
-+ To compile this driver as a module, choose M here: the module will be
-+ called huawei_cdc_ncm.ko.
-+
-+config USB_NET_CDC_MBIM
-+ tristate "CDC MBIM support"
-+ depends on m
-+ depends on USB_USBNET
-+ select USB_WDM
-+ select USB_NET_CDC_NCM
-+ help
-+ This driver provides support for CDC MBIM (Mobile Broadband
-+ Interface Model) devices. The CDC MBIM specification is
-+ available from <http://www.usb.org/>.
-+
-+ MBIM devices require configuration using the management
-+ protocol defined by the MBIM specification. This driver
-+ provides unfiltered access to the MBIM control channel
-+ through the associated /dev/cdc-wdmx character device.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called cdc_mbim.
-+
-+config USB_NET_DM9601
-+ depends on n
-+ tristate "Davicom DM96xx based USB 10/100 ethernet devices"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on CRC32
-+ help
-+ This option adds support for Davicom DM9601/DM9620/DM9621A
-+ based USB 10/100 Ethernet adapters.
-+
-+config USB_NET_SR9700
-+ depends on n
-+ tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on CRC32
-+ help
-+ This option adds support for CoreChip-sz SR9700 based USB 1.1
-+ 10/100 Ethernet adapters.
-+
-+config USB_NET_SR9800
-+ depends on n
-+ tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on CRC32
-+ ---help---
-+ Say Y if you want to use one of the following 100Mbps USB Ethernet
-+ device based on the CoreChip-sz SR9800 chip.
-+
-+ This driver makes the adapter appear as a normal Ethernet interface,
-+ typically on eth0, if it is the only ethernet device, or perhaps on
-+ eth1, if you have a PCI or ISA ethernet card installed.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called sr9800.
-+
-+config USB_NET_SMSC75XX
-+ depends on n
-+ tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on BITREVERSE
-+ depends on CRC16
-+ depends on CRC32
-+ help
-+ This option adds support for SMSC LAN75XX based USB 2.0
-+ Gigabit Ethernet adapters.
-+
-+config USB_NET_SMSC95XX
-+ depends on n
-+ tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"
-+ depends on m
-+ depends on USB_USBNET
-+ depends on BITREVERSE
-+ depends on CRC16
-+ depends on CRC32
-+ help
-+ This option adds support for SMSC LAN95XX based USB 2.0
-+ 10/100 Ethernet adapters.
-+
-+config USB_NET_GL620A
-+ depends on n
-+ tristate "GeneSys GL620USB-A based cables"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a host-to-host cable,
-+ or PC2PC motherboard, with this chip.
-+
-+ Note that the half-duplex "GL620USB" is not supported.
-+
-+config USB_NET_NET1080
-+ depends on n
-+ tristate "NetChip 1080 based cables (Laplink, ...)"
-+ depends on m
-+ default y
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a host-to-host cable based
-+ on this design: one NetChip 1080 chip and supporting logic,
-+ optionally with LEDs that indicate traffic
-+
-+config USB_NET_PLUSB
-+ depends on n
-+ tristate "Prolific PL-2301/2302/25A1 based cables"
-+ depends on m
-+ # if the handshake/init/reset problems, from original 'plusb',
-+ # are ever resolved ... then remove "experimental"
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a host-to-host cable
-+ with one of these chips.
-+
-+config USB_NET_MCS7830
-+ depends on n
-+ tristate "MosChip MCS7830 based Ethernet adapters"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a 10/100 Ethernet USB2
-+ adapter based on the MosChip 7830 controller. This includes
-+ adapters marketed under the DeLOCK brand.
-+
-+config USB_NET_RNDIS_HOST
-+ tristate "Host for RNDIS and ActiveSync devices"
-+ depends on m
-+ depends on USB_USBNET
-+ select USB_NET_CDCETHER
-+ help
-+ This option enables hosting "Remote NDIS" USB networking links,
-+ as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-+ various devices that may only support this protocol. A variant
-+ of this protocol (with even less public documentation) seems to
-+ be at the root of Microsoft's "ActiveSync" too.
-+
-+ Avoid using this protocol unless you have no better options.
-+ The protocol specification is incomplete, and is controlled by
-+ (and for) Microsoft; it isn't an "Open" ecosystem or market.
-+
-+config USB_NET_CDC_SUBSET
-+ depends on n
-+ tristate "Simple USB Network Links (CDC Ethernet subset)"
-+ depends on m
-+ depends on USB_USBNET
-+ default y
-+ help
-+ This driver module supports USB network devices that can work
-+ without any device-specific information. Select it if you have
-+ one of these drivers.
-+
-+ Note that while many USB host-to-host cables can work in this mode,
-+ that may mean not being able to talk to Win32 systems or more
-+ commonly not being able to handle certain events (like replugging
-+ the host on the other end) very well. Also, these devices will
-+ not generally have permanently assigned Ethernet addresses.
-+
-+config USB_ALI_M5632
-+ bool "ALi M5632 based 'USB 2.0 Data Link' cables"
-+ depends on USB_NET_CDC_SUBSET
-+ help
-+ Choose this option if you're using a host-to-host cable
-+ based on this design, which supports USB 2.0 high speed.
-+
-+config USB_AN2720
-+ bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
-+ depends on USB_NET_CDC_SUBSET
-+ help
-+ Choose this option if you're using a host-to-host cable
-+ based on this design. Note that AnchorChips is now a
-+ Cypress brand.
-+
-+config USB_BELKIN
-+ bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
-+ depends on USB_NET_CDC_SUBSET
-+ default y
-+ help
-+ Choose this option if you're using a host-to-host cable
-+ based on this design: two NetChip 2890 chips and an Atmel
-+ microcontroller, with LEDs that indicate traffic.
-+
-+config USB_ARMLINUX
-+ bool "Embedded ARM Linux links (iPaq, ...)"
-+ depends on USB_NET_CDC_SUBSET
-+ default y
-+ help
-+ Choose this option to support the "usb-eth" networking driver
-+ used by most of the ARM Linux community with device controllers
-+ such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities
-+ in some PXA versions of the "blob" boot loader.
-+
-+ Linux-based "Gumstix" PXA-25x based systems use this protocol
-+ to talk with other Linux systems.
-+
-+ Although the ROMs shipped with Sharp Zaurus products use a
-+ different link level framing protocol, you can have them use
-+ this simpler protocol by installing a different kernel.
-+
-+config USB_EPSON2888
-+ bool "Epson 2888 based firmware (DEVELOPMENT)"
-+ depends on USB_NET_CDC_SUBSET
-+ help
-+ Choose this option to support the usb networking links used
-+ by some sample firmware from Epson.
-+
-+config USB_KC2190
-+ bool "KT Technology KC2190 based cables (InstaNet)"
-+ depends on USB_NET_CDC_SUBSET
-+ help
-+ Choose this option if you're using a host-to-host cable
-+ with one of these chips.
-+
-+config USB_NET_ZAURUS
-+ depends on n
-+ tristate "Sharp Zaurus (stock ROMs) and compatible"
-+ depends on m
-+ depends on USB_USBNET
-+ select USB_NET_CDCETHER
-+ depends on CRC32
-+ default y
-+ help
-+ Choose this option to support the usb networking links used by
-+ Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500.
-+ This also supports some related device firmware, as used in some
-+ PDAs from Olympus and some cell phones from Motorola.
-+
-+ If you install an alternate image, such as the Linux 2.6 based
-+ versions of OpenZaurus, you should no longer need to support this
-+ protocol. Only the "eth-fd" or "net_fd" drivers in these devices
-+ really need this non-conformant variant of CDC Ethernet (or in
-+ some cases CDC MDLM) protocol, not "g_ether".
-+
-+config USB_NET_CX82310_ETH
-+ depends on n
-+ tristate "Conexant CX82310 USB ethernet port"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a Conexant CX82310-based ADSL
-+ router with USB ethernet port. This driver is for routers only,
-+ it will not work with ADSL modems (use cxacru driver instead).
-+
-+config USB_NET_KALMIA
-+ depends on n
-+ tristate "Samsung Kalmia based LTE USB modem"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you have a Samsung Kalmia based USB modem
-+ as Samsung GT-B3730.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called kalmia.
-+
-+config USB_NET_QMI_WWAN
-+ tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems"
-+ depends on m
-+ depends on USB_USBNET
-+ select USB_WDM
-+ help
-+ Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem
-+ (MDM) chipsets. Examples of such devices are
-+ * Huawei E392/E398
-+
-+ This driver will only drive the ethernet part of the chips.
-+ The devices require additional configuration to be usable.
-+ Multiple management interfaces with linux drivers are
-+ available:
-+
-+ * option: AT commands on /dev/ttyUSBx
-+ * cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx
-+
-+ A modem manager with support for QMI is recommended.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called qmi_wwan.
-+
-+config USB_HSO
-+ depends on n
-+ tristate "Option USB High Speed Mobile Devices"
-+ depends on m
-+ depends on USB && RFKILL && TTY
-+ default n
-+ help
-+ Choose this option if you have an Option HSDPA/HSUPA card.
-+ These cards support downlink speeds of 7.2Mbps or greater.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called hso.
-+
-+config USB_NET_INT51X1
-+ depends on n
-+ tristate "Intellon PLC based usb adapter"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you're using a 14Mb USB-based PLC
-+ (Powerline Communications) solution with an Intellon
-+ INT51x1/INT5200 chip, like the "devolo dLan duo".
-+
-+config USB_CDC_PHONET
-+ depends on n
-+ tristate "CDC Phonet support"
-+ depends on m
-+ depends on PHONET
-+ help
-+ Choose this option to support the Phonet interface to a Nokia
-+ cellular modem, as found on most Nokia handsets with the
-+ "PC suite" USB profile.
-+
-+config USB_IPHETH
-+ depends on n
-+ tristate "Apple iPhone USB Ethernet driver"
-+ depends on m
-+ default n
-+ ---help---
-+ Module used to share Internet connection (tethering) from your
-+ iPhone (Original, 3G and 3GS) to your system.
-+ Note that you need userspace libraries and programs that are needed
-+ to pair your device with your system and that understand the iPhone
-+ protocol.
-+
-+ For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver
-+
-+config USB_SIERRA_NET
-+ tristate "USB-to-WWAN Driver for Sierra Wireless modems"
-+ depends on m
-+ depends on USB_USBNET
-+ help
-+ Choose this option if you have a Sierra Wireless USB-to-WWAN device.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called sierra_net.
-+
-+config USB_VL600
-+ depends on n
-+ tristate "LG VL600 modem dongle"
-+ depends on m
-+ depends on USB_NET_CDCETHER && TTY
-+ select USB_ACM
-+ help
-+ Select this if you want to use an LG Electronics 4G/LTE usb modem
-+ called VL600. This driver only handles the ethernet
-+ interface exposed by the modem firmware. To establish a connection
-+ you will first need a userspace program that sends the right
-+ command to the modem through its CDC ACM port, and most
-+ likely also a DHCP client. See this thread about using the
-+ 4G modem from Verizon:
-+
-+ http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
-+
-+endif # USB_NET_DRIVERS
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/lg-vl600.c backports-4.2.6-1/drivers/net/usb/lg-vl600.c
---- backports-4.2.6-1.org/drivers/net/usb/lg-vl600.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/lg-vl600.c 2016-06-28 14:35:17.991973886 +0200
-@@ -0,0 +1,353 @@
-+/*
-+ * Ethernet interface part of the LG VL600 LTE modem (4G dongle)
-+ *
-+ * Copyright (C) 2011 Intel Corporation
-+ * Author: Andrzej Zaborowski <balrogg@gmail.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/if_ether.h>
-+#include <linux/if_arp.h>
-+#include <linux/inetdevice.h>
-+#include <linux/module.h>
-+
-+/*
-+ * The device has a CDC ACM port for modem control (it claims to be
-+ * CDC ACM anyway) and a CDC Ethernet port for actual network data.
-+ * It will however ignore data on both ports that is not encapsulated
-+ * in a specific way, any data returned is also encapsulated the same
-+ * way. The headers don't seem to follow any popular standard.
-+ *
-+ * This driver adds and strips these headers from the ethernet frames
-+ * sent/received from the CDC Ethernet port. The proprietary header
-+ * replaces the standard ethernet header in a packet so only actual
-+ * ethernet frames are allowed. The headers allow some form of
-+ * multiplexing by using non standard values of the .h_proto field.
-+ * Windows/Mac drivers do send a couple of such frames to the device
-+ * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what
-+ * seems to be) a flag in the .dummy_flags. This doesn't seem necessary
-+ * for modem operation but can possibly be used for GPS or other funcitons.
-+ */
-+
-+struct vl600_frame_hdr {
-+ __le32 len;
-+ __le32 serial;
-+ __le32 pkt_cnt;
-+ __le32 dummy_flags;
-+ __le32 dummy;
-+ __le32 magic;
-+} __attribute__((packed));
-+
-+struct vl600_pkt_hdr {
-+ __le32 dummy[2];
-+ __le32 len;
-+ __be16 h_proto;
-+} __attribute__((packed));
-+
-+struct vl600_state {
-+ struct sk_buff *current_rx_buf;
-+};
-+
-+static int vl600_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ int ret;
-+ struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL);
-+
-+ if (!s)
-+ return -ENOMEM;
-+
-+ ret = usbnet_cdc_bind(dev, intf);
-+ if (ret) {
-+ kfree(s);
-+ return ret;
-+ }
-+
-+ dev->driver_priv = s;
-+
-+ /* ARP packets don't go through, but they're also of no use. The
-+ * subnet has only two hosts anyway: us and the gateway / DHCP
-+ * server (probably simulated by modem firmware or network operator)
-+ * whose address changes everytime we connect to the intarwebz and
-+ * who doesn't bother answering ARP requests either. So hardware
-+ * addresses have no meaning, the destination and the source of every
-+ * packet depend only on whether it is on the IN or OUT endpoint. */
-+ dev->net->flags |= IFF_NOARP;
-+ /* IPv6 NDP relies on multicast. Enable it by default. */
-+ dev->net->flags |= IFF_MULTICAST;
-+
-+ return ret;
-+}
-+
-+static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct vl600_state *s = dev->driver_priv;
-+
-+ if (s->current_rx_buf)
-+ dev_kfree_skb(s->current_rx_buf);
-+
-+ kfree(s);
-+
-+ return usbnet_cdc_unbind(dev, intf);
-+}
-+
-+static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct vl600_frame_hdr *frame;
-+ struct vl600_pkt_hdr *packet;
-+ struct ethhdr *ethhdr;
-+ int packet_len, count;
-+ struct sk_buff *buf = skb;
-+ struct sk_buff *clone;
-+ struct vl600_state *s = dev->driver_priv;
-+
-+ /* Frame lengths are generally 4B multiplies but every couple of
-+ * hours there's an odd number of bytes sized yet correct frame,
-+ * so don't require this. */
-+
-+ /* Allow a packet (or multiple packets batched together) to be
-+ * split across many frames. We don't allow a new batch to
-+ * begin in the same frame another one is ending however, and no
-+ * leading or trailing pad bytes. */
-+ if (s->current_rx_buf) {
-+ frame = (struct vl600_frame_hdr *) s->current_rx_buf->data;
-+ if (skb->len + s->current_rx_buf->len >
-+ le32_to_cpup(&frame->len)) {
-+ netif_err(dev, ifup, dev->net, "Fragment too long\n");
-+ dev->net->stats.rx_length_errors++;
-+ goto error;
-+ }
-+
-+ buf = s->current_rx_buf;
-+ memcpy(skb_put(buf, skb->len), skb->data, skb->len);
-+ } else if (skb->len < 4) {
-+ netif_err(dev, ifup, dev->net, "Frame too short\n");
-+ dev->net->stats.rx_length_errors++;
-+ goto error;
-+ }
-+
-+ frame = (struct vl600_frame_hdr *) buf->data;
-+ /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48),
-+ * otherwise we may run out of memory w/a bad packet */
-+ if (ntohl(frame->magic) != 0x53544448 &&
-+ ntohl(frame->magic) != 0x44544d48)
-+ goto error;
-+
-+ if (buf->len < sizeof(*frame) ||
-+ buf->len != le32_to_cpup(&frame->len)) {
-+ /* Save this fragment for later assembly */
-+ if (s->current_rx_buf)
-+ return 0;
-+
-+ s->current_rx_buf = skb_copy_expand(skb, 0,
-+ le32_to_cpup(&frame->len), GFP_ATOMIC);
-+ if (!s->current_rx_buf) {
-+ netif_err(dev, ifup, dev->net, "Reserving %i bytes "
-+ "for packet assembly failed.\n",
-+ le32_to_cpup(&frame->len));
-+ dev->net->stats.rx_errors++;
-+ }
-+
-+ return 0;
-+ }
-+
-+ count = le32_to_cpup(&frame->pkt_cnt);
-+
-+ skb_pull(buf, sizeof(*frame));
-+
-+ while (count--) {
-+ if (buf->len < sizeof(*packet)) {
-+ netif_err(dev, ifup, dev->net, "Packet too short\n");
-+ goto error;
-+ }
-+
-+ packet = (struct vl600_pkt_hdr *) buf->data;
-+ packet_len = sizeof(*packet) + le32_to_cpup(&packet->len);
-+ if (packet_len > buf->len) {
-+ netif_err(dev, ifup, dev->net,
-+ "Bad packet length stored in header\n");
-+ goto error;
-+ }
-+
-+ /* Packet header is same size as the ethernet header
-+ * (sizeof(*packet) == sizeof(*ethhdr)), additionally
-+ * the h_proto field is in the same place so we just leave it
-+ * alone and fill in the remaining fields.
-+ */
-+ ethhdr = (struct ethhdr *) skb->data;
-+ if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP &&
-+ buf->len > 0x26) {
-+ /* Copy the addresses from packet contents */
-+ memcpy(ethhdr->h_source,
-+ &buf->data[sizeof(*ethhdr) + 0x8],
-+ ETH_ALEN);
-+ memcpy(ethhdr->h_dest,
-+ &buf->data[sizeof(*ethhdr) + 0x12],
-+ ETH_ALEN);
-+ } else {
-+ eth_zero_addr(ethhdr->h_source);
-+ memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN);
-+
-+ /* Inbound IPv6 packets have an IPv4 ethertype (0x800)
-+ * for some reason. Peek at the L3 header to check
-+ * for IPv6 packets, and set the ethertype to IPv6
-+ * (0x86dd) so Linux can understand it.
-+ */
-+ if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
-+ ethhdr->h_proto = htons(ETH_P_IPV6);
-+ }
-+
-+ if (count) {
-+ /* Not the last packet in this batch */
-+ clone = skb_clone(buf, GFP_ATOMIC);
-+ if (!clone)
-+ goto error;
-+
-+ skb_trim(clone, packet_len);
-+ usbnet_skb_return(dev, clone);
-+
-+ skb_pull(buf, (packet_len + 3) & ~3);
-+ } else {
-+ skb_trim(buf, packet_len);
-+
-+ if (s->current_rx_buf) {
-+ usbnet_skb_return(dev, buf);
-+ s->current_rx_buf = NULL;
-+ return 0;
-+ }
-+
-+ return 1;
-+ }
-+ }
-+
-+error:
-+ if (s->current_rx_buf) {
-+ dev_kfree_skb_any(s->current_rx_buf);
-+ s->current_rx_buf = NULL;
-+ }
-+ dev->net->stats.rx_errors++;
-+ return 0;
-+}
-+
-+static struct sk_buff *vl600_tx_fixup(struct usbnet *dev,
-+ struct sk_buff *skb, gfp_t flags)
-+{
-+ struct sk_buff *ret;
-+ struct vl600_frame_hdr *frame;
-+ struct vl600_pkt_hdr *packet;
-+ static uint32_t serial = 1;
-+ int orig_len = skb->len - sizeof(struct ethhdr);
-+ int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3;
-+
-+ frame = (struct vl600_frame_hdr *) skb->data;
-+ if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len))
-+ return skb; /* Already encapsulated? */
-+
-+ if (skb->len < sizeof(struct ethhdr))
-+ /* Drop, device can only deal with ethernet packets */
-+ return NULL;
-+
-+ if (!skb_cloned(skb)) {
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+
-+ if (tailroom >= full_len - skb->len - sizeof(*frame) &&
-+ headroom >= sizeof(*frame))
-+ /* There's enough head and tail room */
-+ goto encapsulate;
-+
-+ if (headroom + tailroom + skb->len >= full_len) {
-+ /* There's enough total room, just readjust */
-+ skb->data = memmove(skb->head + sizeof(*frame),
-+ skb->data, skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ goto encapsulate;
-+ }
-+ }
-+
-+ /* Alloc a new skb with the required size */
-+ ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len -
-+ skb->len - sizeof(struct vl600_frame_hdr), flags);
-+ dev_kfree_skb_any(skb);
-+ if (!ret)
-+ return ret;
-+ skb = ret;
-+
-+encapsulate:
-+ /* Packet header is same size as ethernet packet header
-+ * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the
-+ * h_proto field is in the same place so we just leave it alone and
-+ * overwrite the remaining fields.
-+ */
-+ packet = (struct vl600_pkt_hdr *) skb->data;
-+ /* The VL600 wants IPv6 packets to have an IPv4 ethertype
-+ * Since this modem only supports IPv4 and IPv6, just set all
-+ * frames to 0x0800 (ETH_P_IP)
-+ */
-+ packet->h_proto = htons(ETH_P_IP);
-+ memset(&packet->dummy, 0, sizeof(packet->dummy));
-+ packet->len = cpu_to_le32(orig_len);
-+
-+ frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame));
-+ memset(frame, 0, sizeof(*frame));
-+ frame->len = cpu_to_le32(full_len);
-+ frame->serial = cpu_to_le32(serial++);
-+ frame->pkt_cnt = cpu_to_le32(1);
-+
-+ if (skb->len < full_len) /* Pad */
-+ skb_put(skb, full_len - skb->len);
-+
-+ return skb;
-+}
-+
-+static const struct driver_info vl600_info = {
-+ .description = "LG VL600 modem",
-+ .flags = FLAG_RX_ASSEMBLE | FLAG_WWAN,
-+ .bind = vl600_bind,
-+ .unbind = vl600_unbind,
-+ .status = usbnet_cdc_status,
-+ .rx_fixup = vl600_rx_fixup,
-+ .tx_fixup = vl600_tx_fixup,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
-+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-+ .driver_info = (unsigned long) &vl600_info,
-+ },
-+ {}, /* End */
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver lg_vl600_driver = {
-+ .name = "lg-vl600",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(lg_vl600_driver);
-+
-+MODULE_AUTHOR("Anrzej Zaborowski");
-+MODULE_DESCRIPTION("LG-VL600 modem's ethernet link");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/Makefile backports-4.2.6-1/drivers/net/usb/Makefile
---- backports-4.2.6-1.org/drivers/net/usb/Makefile 2015-11-15 22:19:40.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/Makefile 2016-06-28 14:35:17.991973886 +0200
-@@ -1,39 +1,40 @@
- #
- # Makefile for USB Network drivers
- #
--#
--#obj-$(CPTCFG_USB_CATC) += catc.o
--#obj-$(CPTCFG_USB_KAWETH) += kaweth.o
--#obj-$(CPTCFG_USB_PEGASUS) += pegasus.o
--#obj-$(CPTCFG_USB_RTL8150) += rtl8150.o
--#obj-$(CPTCFG_USB_RTL8152) += r8152.o
--#obj-$(CPTCFG_USB_HSO) += hso.o
--#obj-$(CPTCFG_USB_NET_AX8817X) += asix.o
--#obj-$(CPTCFG_USB_NET_AX88179_178A) += ax88179_178a.o
-+
-+obj-$(CPTCFG_USB_CATC) += catc.o
-+obj-$(CPTCFG_USB_KAWETH) += kaweth.o
-+obj-$(CPTCFG_USB_PEGASUS) += pegasus.o
-+obj-$(CPTCFG_USB_RTL8150) += rtl8150.o
-+obj-$(CPTCFG_USB_RTL8152) += r8152.o
-+obj-$(CPTCFG_USB_HSO) += hso.o
-+obj-$(CPTCFG_USB_NET_AX8817X) += asix.o
-+asix-y := asix_devices.o asix_common.o ax88172a.o
-+obj-$(CPTCFG_USB_NET_AX88179_178A) += ax88179_178a.o
- obj-$(CPTCFG_USB_NET_CDCETHER) += cdc_ether.o
--#obj-$(CPTCFG_USB_NET_CDC_EEM) += cdc_eem.o
--#obj-$(CPTCFG_USB_NET_DM9601) += dm9601.o
--#obj-$(CPTCFG_USB_NET_SR9700) += sr9700.o
--#obj-$(CPTCFG_USB_NET_SR9800) += sr9800.o
--#obj-$(CPTCFG_USB_NET_SMSC75XX) += smsc75xx.o
--#obj-$(CPTCFG_USB_NET_SMSC95XX) += smsc95xx.o
--#obj-$(CPTCFG_USB_NET_GL620A) += gl620a.o
--#obj-$(CPTCFG_USB_NET_NET1080) += net1080.o
--#obj-$(CPTCFG_USB_NET_PLUSB) += plusb.o
-+obj-$(CPTCFG_USB_NET_CDC_EEM) += cdc_eem.o
-+obj-$(CPTCFG_USB_NET_DM9601) += dm9601.o
-+obj-$(CPTCFG_USB_NET_SR9700) += sr9700.o
-+obj-$(CPTCFG_USB_NET_SR9800) += sr9800.o
-+obj-$(CPTCFG_USB_NET_SMSC75XX) += smsc75xx.o
-+obj-$(CPTCFG_USB_NET_SMSC95XX) += smsc95xx.o
-+obj-$(CPTCFG_USB_NET_GL620A) += gl620a.o
-+obj-$(CPTCFG_USB_NET_NET1080) += net1080.o
-+obj-$(CPTCFG_USB_NET_PLUSB) += plusb.o
- obj-$(CPTCFG_USB_NET_RNDIS_HOST) += rndis_host.o
--#obj-$(CPTCFG_USB_NET_CDC_SUBSET) += cdc_subset.o
--#obj-$(CPTCFG_USB_NET_ZAURUS) += zaurus.o
--#obj-$(CPTCFG_USB_NET_MCS7830) += mcs7830.o
-+obj-$(CPTCFG_USB_NET_CDC_SUBSET) += cdc_subset.o
-+obj-$(CPTCFG_USB_NET_ZAURUS) += zaurus.o
-+obj-$(CPTCFG_USB_NET_MCS7830) += mcs7830.o
- obj-$(CPTCFG_USB_USBNET) += usbnet.o
--#obj-$(CPTCFG_USB_NET_INT51X1) += int51x1.o
--#obj-$(CPTCFG_USB_CDC_PHONET) += cdc-phonet.o
--#obj-$(CPTCFG_USB_NET_KALMIA) += kalmia.o
--#obj-$(CPTCFG_USB_IPHETH) += ipheth.o
-+obj-$(CPTCFG_USB_NET_INT51X1) += int51x1.o
-+obj-$(CPTCFG_USB_CDC_PHONET) += cdc-phonet.o
-+obj-$(CPTCFG_USB_NET_KALMIA) += kalmia.o
-+obj-$(CPTCFG_USB_IPHETH) += ipheth.o
- obj-$(CPTCFG_USB_SIERRA_NET) += sierra_net.o
--#obj-$(CPTCFG_USB_NET_CX82310_ETH) += cx82310_eth.o
-+obj-$(CPTCFG_USB_NET_CX82310_ETH) += cx82310_eth.o
- obj-$(CPTCFG_USB_NET_CDC_NCM) += cdc_ncm.o
--#obj-$(CPTCFG_USB_NET_HUAWEI_CDC_NCM) += huawei_cdc_ncm.o
--#obj-$(CPTCFG_USB_VL600) += lg-vl600.o
-+obj-$(CPTCFG_USB_NET_HUAWEI_CDC_NCM) += huawei_cdc_ncm.o
-+obj-$(CPTCFG_USB_VL600) += lg-vl600.o
- obj-$(CPTCFG_USB_NET_QMI_WWAN) += qmi_wwan.o
- obj-$(CPTCFG_USB_NET_CDC_MBIM) += cdc_mbim.o
-
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/mcs7830.c backports-4.2.6-1/drivers/net/usb/mcs7830.c
---- backports-4.2.6-1.org/drivers/net/usb/mcs7830.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/mcs7830.c 2016-06-28 14:35:17.995307218 +0200
-@@ -0,0 +1,643 @@
-+/*
-+ * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
-+ *
-+ * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
-+ *
-+ * Copyright (C) 2010 Andreas Mohr <andi@lisas.de>
-+ * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
-+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
-+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
-+ * Copyright (c) 2002-2003 TiVo Inc.
-+ *
-+ * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!).
-+ *
-+ * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"),
-+ * per active notification by manufacturer
-+ *
-+ * TODO:
-+ * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?)
-+ * - implement ethtool_ops get_pauseparam/set_pauseparam
-+ * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!)
-+ * - implement get_eeprom/[set_eeprom]
-+ * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII)
-+ * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs,
-+ * can access only ~ 24, remaining user buffer is uninitialized garbage
-+ * - anything else?
-+ *
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/crc32.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/slab.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+
-+/* requests */
-+#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \
-+ USB_RECIP_DEVICE)
-+#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \
-+ USB_RECIP_DEVICE)
-+#define MCS7830_RD_BREQ 0x0E
-+#define MCS7830_WR_BREQ 0x0D
-+
-+#define MCS7830_CTRL_TIMEOUT 1000
-+#define MCS7830_MAX_MCAST 64
-+
-+#define MCS7830_VENDOR_ID 0x9710
-+#define MCS7832_PRODUCT_ID 0x7832
-+#define MCS7830_PRODUCT_ID 0x7830
-+#define MCS7730_PRODUCT_ID 0x7730
-+
-+#define SITECOM_VENDOR_ID 0x0DF6
-+#define LN_030_PRODUCT_ID 0x0021
-+
-+#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
-+ ADVERTISE_100HALF | ADVERTISE_10FULL | \
-+ ADVERTISE_10HALF | ADVERTISE_CSMA)
-+
-+/* HIF_REG_XX corresponding index value */
-+enum {
-+ HIF_REG_MULTICAST_HASH = 0x00,
-+ HIF_REG_PACKET_GAP1 = 0x08,
-+ HIF_REG_PACKET_GAP2 = 0x09,
-+ HIF_REG_PHY_DATA = 0x0a,
-+ HIF_REG_PHY_CMD1 = 0x0c,
-+ HIF_REG_PHY_CMD1_READ = 0x40,
-+ HIF_REG_PHY_CMD1_WRITE = 0x20,
-+ HIF_REG_PHY_CMD1_PHYADDR = 0x01,
-+ HIF_REG_PHY_CMD2 = 0x0d,
-+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
-+ HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
-+ HIF_REG_CONFIG = 0x0e,
-+ /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */
-+ HIF_REG_CONFIG_CFG = 0x80,
-+ HIF_REG_CONFIG_SPEED100 = 0x40,
-+ HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
-+ HIF_REG_CONFIG_RXENABLE = 0x10,
-+ HIF_REG_CONFIG_TXENABLE = 0x08,
-+ HIF_REG_CONFIG_SLEEPMODE = 0x04,
-+ HIF_REG_CONFIG_ALLMULTICAST = 0x02,
-+ HIF_REG_CONFIG_PROMISCUOUS = 0x01,
-+ HIF_REG_ETHERNET_ADDR = 0x0f,
-+ HIF_REG_FRAME_DROP_COUNTER = 0x15, /* 0..ff; reset: 0 */
-+ HIF_REG_PAUSE_THRESHOLD = 0x16,
-+ HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
-+};
-+
-+/* Trailing status byte in Ethernet Rx frame */
-+enum {
-+ MCS7830_RX_SHORT_FRAME = 0x01, /* < 64 bytes */
-+ MCS7830_RX_LENGTH_ERROR = 0x02, /* framelen != Ethernet length field */
-+ MCS7830_RX_ALIGNMENT_ERROR = 0x04, /* non-even number of nibbles */
-+ MCS7830_RX_CRC_ERROR = 0x08,
-+ MCS7830_RX_LARGE_FRAME = 0x10, /* > 1518 bytes */
-+ MCS7830_RX_FRAME_CORRECT = 0x20, /* frame is correct */
-+ /* [7:6] reserved */
-+};
-+
-+struct mcs7830_data {
-+ u8 multi_filter[8];
-+ u8 config;
-+};
-+
-+static const char driver_name[] = "MOSCHIP usb-ethernet driver";
-+
-+static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
-+{
-+ return usbnet_read_cmd(dev, MCS7830_RD_BREQ, MCS7830_RD_BMREQ,
-+ 0x0000, index, data, size);
-+}
-+
-+static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data)
-+{
-+ return usbnet_write_cmd(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ,
-+ 0x0000, index, data, size);
-+}
-+
-+static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
-+{
-+ usbnet_write_cmd_async(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ,
-+ 0x0000, index, data, size);
-+}
-+
-+static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr)
-+{
-+ int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
-+ if (ret < 0)
-+ return ret;
-+ return 0;
-+}
-+
-+static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr)
-+{
-+ int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr);
-+
-+ if (ret < 0)
-+ return ret;
-+ return 0;
-+}
-+
-+static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
-+{
-+ int ret;
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct sockaddr *addr = p;
-+
-+ if (netif_running(netdev))
-+ return -EBUSY;
-+
-+ if (!is_valid_ether_addr(addr->sa_data))
-+ return -EADDRNOTAVAIL;
-+
-+ ret = mcs7830_hif_set_mac_address(dev, addr->sa_data);
-+
-+ if (ret < 0)
-+ return ret;
-+
-+ /* it worked --> adopt it on netdev side */
-+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-+
-+ return 0;
-+}
-+
-+static int mcs7830_read_phy(struct usbnet *dev, u8 index)
-+{
-+ int ret;
-+ int i;
-+ __le16 val;
-+
-+ u8 cmd[2] = {
-+ HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
-+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
-+ };
-+
-+ mutex_lock(&dev->phy_mutex);
-+ /* write the MII command */
-+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* wait for the data to become valid, should be within < 1ms */
-+ for (i = 0; i < 10; i++) {
-+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
-+ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
-+ break;
-+ ret = -EIO;
-+ msleep(1);
-+ }
-+ if (ret < 0)
-+ goto out;
-+
-+ /* read actual register contents */
-+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
-+ if (ret < 0)
-+ goto out;
-+ ret = le16_to_cpu(val);
-+ dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
-+ index, val, i);
-+out:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
-+{
-+ int ret;
-+ int i;
-+ __le16 le_val;
-+
-+ u8 cmd[2] = {
-+ HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
-+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
-+ };
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ /* write the new register contents */
-+ le_val = cpu_to_le16(val);
-+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* write the MII command */
-+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* wait for the command to be accepted by the PHY */
-+ for (i = 0; i < 10; i++) {
-+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
-+ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
-+ break;
-+ ret = -EIO;
-+ msleep(1);
-+ }
-+ if (ret < 0)
-+ goto out;
-+
-+ ret = 0;
-+ dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
-+ index, val, i);
-+out:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+/*
-+ * This algorithm comes from the original mcs7830 version 1.4 driver,
-+ * not sure if it is needed.
-+ */
-+static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
-+{
-+ int ret;
-+ /* Enable all media types */
-+ ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
-+
-+ /* First reset BMCR */
-+ if (!ret)
-+ ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
-+ /* Enable Auto Neg */
-+ if (!ret)
-+ ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
-+ /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
-+ if (!ret)
-+ ret = mcs7830_write_phy(dev, MII_BMCR,
-+ BMCR_ANENABLE | BMCR_ANRESTART );
-+ return ret;
-+}
-+
-+
-+/*
-+ * if we can read register 22, the chip revision is C or higher
-+ */
-+static int mcs7830_get_rev(struct usbnet *dev)
-+{
-+ u8 dummy[2];
-+ int ret;
-+ ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy);
-+ if (ret > 0)
-+ return 2; /* Rev C or later */
-+ return 1; /* earlier revision */
-+}
-+
-+/*
-+ * On rev. C we need to set the pause threshold
-+ */
-+static void mcs7830_rev_C_fixup(struct usbnet *dev)
-+{
-+ u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
-+ int retry;
-+
-+ for (retry = 0; retry < 2; retry++) {
-+ if (mcs7830_get_rev(dev) == 2) {
-+ dev_info(&dev->udev->dev, "applying rev.C fixup\n");
-+ mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
-+ 1, &pause_threshold);
-+ }
-+ msleep(1);
-+ }
-+}
-+
-+static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
-+ int location)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ return mcs7830_read_phy(dev, location);
-+}
-+
-+static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
-+ int location, int val)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ mcs7830_write_phy(dev, location, val);
-+}
-+
-+static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev)
-+{
-+ return (struct mcs7830_data *)&dev->data;
-+}
-+
-+static void mcs7830_hif_update_multicast_hash(struct usbnet *dev)
-+{
-+ struct mcs7830_data *data = mcs7830_get_data(dev);
-+ mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
-+ sizeof data->multi_filter,
-+ data->multi_filter);
-+}
-+
-+static void mcs7830_hif_update_config(struct usbnet *dev)
-+{
-+ /* implementation specific to data->config
-+ (argument needs to be heap-based anyway - USB DMA!) */
-+ struct mcs7830_data *data = mcs7830_get_data(dev);
-+ mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
-+}
-+
-+static void mcs7830_data_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct mcs7830_data *data = mcs7830_get_data(dev);
-+
-+ memset(data->multi_filter, 0, sizeof data->multi_filter);
-+
-+ data->config = HIF_REG_CONFIG_TXENABLE;
-+
-+ /* this should not be needed, but it doesn't work otherwise */
-+ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
-+
-+ if (net->flags & IFF_PROMISC) {
-+ data->config |= HIF_REG_CONFIG_PROMISCUOUS;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > MCS7830_MAX_MCAST) {
-+ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
-+ } else if (netdev_mc_empty(net)) {
-+ /* just broadcast and directed */
-+ } else {
-+ /* We use the 20 byte dev->data
-+ * for our 8 byte filter buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later */
-+ struct netdev_hw_addr *ha;
-+ u32 crc_bits;
-+
-+ /* Build the multicast hash filter. */
-+ netdev_for_each_mc_addr(ha, net) {
-+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
-+ }
-+ }
-+}
-+
-+static int mcs7830_apply_base_config(struct usbnet *dev)
-+{
-+ int ret;
-+
-+ /* re-configure known MAC (suspend case etc.) */
-+ ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr);
-+ if (ret) {
-+ dev_info(&dev->udev->dev, "Cannot set MAC address\n");
-+ goto out;
-+ }
-+
-+ /* Set up PHY */
-+ ret = mcs7830_set_autoneg(dev, 0);
-+ if (ret) {
-+ dev_info(&dev->udev->dev, "Cannot set autoneg\n");
-+ goto out;
-+ }
-+
-+ mcs7830_hif_update_multicast_hash(dev);
-+ mcs7830_hif_update_config(dev);
-+
-+ mcs7830_rev_C_fixup(dev);
-+ ret = 0;
-+out:
-+ return ret;
-+}
-+
-+/* credits go to asix_set_multicast */
-+static void mcs7830_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ mcs7830_data_set_multicast(net);
-+
-+ mcs7830_hif_update_multicast_hash(dev);
-+ mcs7830_hif_update_config(dev);
-+}
-+
-+static int mcs7830_get_regs_len(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ switch (mcs7830_get_rev(dev)) {
-+ case 1:
-+ return 21;
-+ case 2:
-+ return 32;
-+ }
-+ return 0;
-+}
-+
-+static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
-+{
-+ usbnet_get_drvinfo(net, drvinfo);
-+ drvinfo->regdump_len = mcs7830_get_regs_len(net);
-+}
-+
-+static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ regs->version = mcs7830_get_rev(dev);
-+ mcs7830_get_reg(dev, 0, regs->len, data);
-+}
-+
-+static const struct ethtool_ops mcs7830_ethtool_ops = {
-+ .get_drvinfo = mcs7830_get_drvinfo,
-+ .get_regs_len = mcs7830_get_regs_len,
-+ .get_regs = mcs7830_get_regs,
-+
-+ /* common usbnet calls */
-+ .get_link = usbnet_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static const struct net_device_ops mcs7830_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = mcs7830_ioctl,
-+ .ndo_set_rx_mode = mcs7830_set_multicast,
-+ .ndo_set_mac_address = mcs7830_set_mac_address,
-+};
-+
-+static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
-+{
-+ struct net_device *net = dev->net;
-+ int ret;
-+ int retry;
-+
-+ /* Initial startup: Gather MAC address setting from EEPROM */
-+ ret = -EINVAL;
-+ for (retry = 0; retry < 5 && ret; retry++)
-+ ret = mcs7830_hif_get_mac_address(dev, net->dev_addr);
-+ if (ret) {
-+ dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
-+ goto out;
-+ }
-+
-+ mcs7830_data_set_multicast(net);
-+
-+ ret = mcs7830_apply_base_config(dev);
-+ if (ret)
-+ goto out;
-+
-+ net->ethtool_ops = &mcs7830_ethtool_ops;
-+ net->netdev_ops = &mcs7830_netdev_ops;
-+
-+ /* reserve space for the status byte on rx */
-+ dev->rx_urb_size = ETH_FRAME_LEN + 1;
-+
-+ dev->mii.mdio_read = mcs7830_mdio_read;
-+ dev->mii.mdio_write = mcs7830_mdio_write;
-+ dev->mii.dev = net;
-+ dev->mii.phy_id_mask = 0x3f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
-+
-+ ret = usbnet_get_endpoints(dev, udev);
-+out:
-+ return ret;
-+}
-+
-+/* The chip always appends a status byte that we need to strip */
-+static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ u8 status;
-+
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len) {
-+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
-+ return 0;
-+ }
-+
-+ skb_trim(skb, skb->len - 1);
-+ status = skb->data[skb->len];
-+
-+ if (status != MCS7830_RX_FRAME_CORRECT) {
-+ dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
-+
-+ /* hmm, perhaps usbnet.c already sees a globally visible
-+ frame error and increments rx_errors on its own already? */
-+ dev->net->stats.rx_errors++;
-+
-+ if (status & (MCS7830_RX_SHORT_FRAME
-+ |MCS7830_RX_LENGTH_ERROR
-+ |MCS7830_RX_LARGE_FRAME))
-+ dev->net->stats.rx_length_errors++;
-+ if (status & MCS7830_RX_ALIGNMENT_ERROR)
-+ dev->net->stats.rx_frame_errors++;
-+ if (status & MCS7830_RX_CRC_ERROR)
-+ dev->net->stats.rx_crc_errors++;
-+ }
-+
-+ return skb->len > 0;
-+}
-+
-+static void mcs7830_status(struct usbnet *dev, struct urb *urb)
-+{
-+ u8 *buf = urb->transfer_buffer;
-+ bool link, link_changed;
-+
-+ if (urb->actual_length < 16)
-+ return;
-+
-+ link = !(buf[1] == 0x20);
-+ link_changed = netif_carrier_ok(dev->net) != link;
-+ if (link_changed) {
-+ usbnet_link_change(dev, link, 0);
-+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
-+ }
-+}
-+
-+static const struct driver_info moschip_info = {
-+ .description = "MOSCHIP 7830/7832/7730 usb-NET adapter",
-+ .bind = mcs7830_bind,
-+ .rx_fixup = mcs7830_rx_fixup,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .status = mcs7830_status,
-+ .in = 1,
-+ .out = 2,
-+};
-+
-+static const struct driver_info sitecom_info = {
-+ .description = "Sitecom LN-30 usb-NET adapter",
-+ .bind = mcs7830_bind,
-+ .rx_fixup = mcs7830_rx_fixup,
-+ .flags = FLAG_ETHER | FLAG_LINK_INTR,
-+ .status = mcs7830_status,
-+ .in = 1,
-+ .out = 2,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID),
-+ .driver_info = (unsigned long) &moschip_info,
-+ },
-+ {
-+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
-+ .driver_info = (unsigned long) &moschip_info,
-+ },
-+ {
-+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7730_PRODUCT_ID),
-+ .driver_info = (unsigned long) &moschip_info,
-+ },
-+ {
-+ USB_DEVICE(SITECOM_VENDOR_ID, LN_030_PRODUCT_ID),
-+ .driver_info = (unsigned long) &sitecom_info,
-+ },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static int mcs7830_reset_resume (struct usb_interface *intf)
-+{
-+ /* YES, this function is successful enough that ethtool -d
-+ does show same output pre-/post-suspend */
-+
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+
-+ mcs7830_apply_base_config(dev);
-+
-+ usbnet_resume(intf);
-+
-+ return 0;
-+}
-+
-+static struct usb_driver mcs7830_driver = {
-+ .name = driver_name,
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .reset_resume = mcs7830_reset_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(mcs7830_driver);
-+
-+MODULE_DESCRIPTION("USB to network adapter MCS7830)");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/net1080.c backports-4.2.6-1/drivers/net/usb/net1080.c
---- backports-4.2.6-1.org/drivers/net/usb/net1080.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/net1080.c 2016-06-28 14:35:17.995307218 +0200
-@@ -0,0 +1,544 @@
-+/*
-+ * Net1080 based USB host-to-host cables
-+ * Copyright (C) 2000-2005 by David Brownell
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+// #define DEBUG // error path messages, extra info
-+// #define VERBOSE // more; success messages
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+
-+#include <asm/unaligned.h>
-+
-+
-+/*
-+ * Netchip 1080 driver ... http://www.netchip.com
-+ * (Sept 2004: End-of-life announcement has been sent.)
-+ * Used in (some) LapLink cables
-+ */
-+
-+#define frame_errors data[1]
-+
-+/*
-+ * NetChip framing of ethernet packets, supporting additional error
-+ * checks for links that may drop bulk packets from inside messages.
-+ * Odd USB length == always short read for last usb packet.
-+ * - nc_header
-+ * - Ethernet header (14 bytes)
-+ * - payload
-+ * - (optional padding byte, if needed so length becomes odd)
-+ * - nc_trailer
-+ *
-+ * This framing is to be avoided for non-NetChip devices.
-+ */
-+
-+struct nc_header { // packed:
-+ __le16 hdr_len; // sizeof nc_header (LE, all)
-+ __le16 packet_len; // payload size (including ethhdr)
-+ __le16 packet_id; // detects dropped packets
-+#define MIN_HEADER 6
-+
-+ // all else is optional, and must start with:
-+ // __le16 vendorId; // from usb-if
-+ // __le16 productId;
-+} __packed;
-+
-+#define PAD_BYTE ((unsigned char)0xAC)
-+
-+struct nc_trailer {
-+ __le16 packet_id;
-+} __packed;
-+
-+// packets may use FLAG_FRAMING_NC and optional pad
-+#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
-+ + sizeof (struct ethhdr) \
-+ + (mtu) \
-+ + 1 \
-+ + sizeof (struct nc_trailer))
-+
-+#define MIN_FRAMED FRAMED_SIZE(0)
-+
-+/* packets _could_ be up to 64KB... */
-+#define NC_MAX_PACKET 32767
-+
-+
-+/*
-+ * Zero means no timeout; else, how long a 64 byte bulk packet may be queued
-+ * before the hardware drops it. If that's done, the driver will need to
-+ * frame network packets to guard against the dropped USB packets. The win32
-+ * driver sets this for both sides of the link.
-+ */
-+#define NC_READ_TTL_MS ((u8)255) // ms
-+
-+/*
-+ * We ignore most registers and EEPROM contents.
-+ */
-+#define REG_USBCTL ((u8)0x04)
-+#define REG_TTL ((u8)0x10)
-+#define REG_STATUS ((u8)0x11)
-+
-+/*
-+ * Vendor specific requests to read/write data
-+ */
-+#define REQUEST_REGISTER ((u8)0x10)
-+#define REQUEST_EEPROM ((u8)0x11)
-+
-+static int
-+nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
-+{
-+ int status = usbnet_read_cmd(dev, req,
-+ USB_DIR_IN | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE,
-+ 0, regnum, retval_ptr,
-+ sizeof *retval_ptr);
-+ if (status > 0)
-+ status = 0;
-+ if (!status)
-+ le16_to_cpus(retval_ptr);
-+ return status;
-+}
-+
-+static inline int
-+nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)
-+{
-+ return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);
-+}
-+
-+// no retval ... can become async, usable in_interrupt()
-+static void
-+nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)
-+{
-+ usbnet_write_cmd(dev, req,
-+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ value, regnum, NULL, 0);
-+}
-+
-+static inline void
-+nc_register_write(struct usbnet *dev, u8 regnum, u16 value)
-+{
-+ nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);
-+}
-+
-+
-+#if 0
-+static void nc_dump_registers(struct usbnet *dev)
-+{
-+ u8 reg;
-+ u16 *vp = kmalloc(sizeof (u16));
-+
-+ if (!vp)
-+ return;
-+
-+ netdev_dbg(dev->net, "registers:\n");
-+ for (reg = 0; reg < 0x20; reg++) {
-+ int retval;
-+
-+ // reading some registers is trouble
-+ if (reg >= 0x08 && reg <= 0xf)
-+ continue;
-+ if (reg >= 0x12 && reg <= 0x1e)
-+ continue;
-+
-+ retval = nc_register_read(dev, reg, vp);
-+ if (retval < 0)
-+ netdev_dbg(dev->net, "reg [0x%x] ==> error %d\n",
-+ reg, retval);
-+ else
-+ netdev_dbg(dev->net, "reg [0x%x] = 0x%x\n", reg, *vp);
-+ }
-+ kfree(vp);
-+}
-+#endif
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * Control register
-+ */
-+
-+#define USBCTL_WRITABLE_MASK 0x1f0f
-+// bits 15-13 reserved, r/o
-+#define USBCTL_ENABLE_LANG (1 << 12)
-+#define USBCTL_ENABLE_MFGR (1 << 11)
-+#define USBCTL_ENABLE_PROD (1 << 10)
-+#define USBCTL_ENABLE_SERIAL (1 << 9)
-+#define USBCTL_ENABLE_DEFAULTS (1 << 8)
-+// bits 7-4 reserved, r/o
-+#define USBCTL_FLUSH_OTHER (1 << 3)
-+#define USBCTL_FLUSH_THIS (1 << 2)
-+#define USBCTL_DISCONN_OTHER (1 << 1)
-+#define USBCTL_DISCONN_THIS (1 << 0)
-+
-+static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)
-+{
-+ netif_dbg(dev, link, dev->net,
-+ "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n",
-+ dev->udev->bus->bus_name, dev->udev->devpath,
-+ usbctl,
-+ (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
-+ (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
-+ (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
-+ (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
-+ (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
-+
-+ (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
-+ (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
-+
-+ (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
-+ (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
-+
-+ usbctl & ~USBCTL_WRITABLE_MASK);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * Status register
-+ */
-+
-+#define STATUS_PORT_A (1 << 15)
-+
-+#define STATUS_CONN_OTHER (1 << 14)
-+#define STATUS_SUSPEND_OTHER (1 << 13)
-+#define STATUS_MAILBOX_OTHER (1 << 12)
-+#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03)
-+
-+#define STATUS_CONN_THIS (1 << 6)
-+#define STATUS_SUSPEND_THIS (1 << 5)
-+#define STATUS_MAILBOX_THIS (1 << 4)
-+#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03)
-+
-+#define STATUS_UNSPEC_MASK 0x0c8c
-+#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK))
-+
-+
-+static inline void nc_dump_status(struct usbnet *dev, u16 status)
-+{
-+ netif_dbg(dev, link, dev->net,
-+ "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n",
-+ dev->udev->bus->bus_name, dev->udev->devpath,
-+ status,
-+
-+ // XXX the packet counts don't seem right
-+ // (1 at reset, not 0); maybe UNSPEC too
-+
-+ (status & STATUS_PORT_A) ? 'A' : 'B',
-+ STATUS_PACKETS_THIS(status),
-+ (status & STATUS_CONN_THIS) ? " CON" : "",
-+ (status & STATUS_SUSPEND_THIS) ? " SUS" : "",
-+ (status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
-+
-+ STATUS_PACKETS_OTHER(status),
-+ (status & STATUS_CONN_OTHER) ? " CON" : "",
-+ (status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
-+ (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
-+
-+ status & STATUS_UNSPEC_MASK);
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * TTL register
-+ */
-+
-+#define TTL_THIS(ttl) (0x00ff & ttl)
-+#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8))
-+#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this))))
-+
-+static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl)
-+{
-+ netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n",
-+ dev->udev->bus->bus_name, dev->udev->devpath,
-+ ttl, TTL_THIS(ttl), TTL_OTHER(ttl));
-+}
-+
-+/*-------------------------------------------------------------------------*/
-+
-+static int net1080_reset(struct usbnet *dev)
-+{
-+ u16 usbctl, status, ttl;
-+ u16 vp;
-+ int retval;
-+
-+ // nc_dump_registers(dev);
-+
-+ if ((retval = nc_register_read(dev, REG_STATUS, &vp)) < 0) {
-+ netdev_dbg(dev->net, "can't read %s-%s status: %d\n",
-+ dev->udev->bus->bus_name, dev->udev->devpath, retval);
-+ goto done;
-+ }
-+ status = vp;
-+ nc_dump_status(dev, status);
-+
-+ if ((retval = nc_register_read(dev, REG_USBCTL, &vp)) < 0) {
-+ netdev_dbg(dev->net, "can't read USBCTL, %d\n", retval);
-+ goto done;
-+ }
-+ usbctl = vp;
-+ nc_dump_usbctl(dev, usbctl);
-+
-+ nc_register_write(dev, REG_USBCTL,
-+ USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
-+
-+ if ((retval = nc_register_read(dev, REG_TTL, &vp)) < 0) {
-+ netdev_dbg(dev->net, "can't read TTL, %d\n", retval);
-+ goto done;
-+ }
-+ ttl = vp;
-+ // nc_dump_ttl(dev, ttl);
-+
-+ nc_register_write(dev, REG_TTL,
-+ MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );
-+ netdev_dbg(dev->net, "assigned TTL, %d ms\n", NC_READ_TTL_MS);
-+
-+ netif_info(dev, link, dev->net, "port %c, peer %sconnected\n",
-+ (status & STATUS_PORT_A) ? 'A' : 'B',
-+ (status & STATUS_CONN_OTHER) ? "" : "dis");
-+ retval = 0;
-+
-+done:
-+ return retval;
-+}
-+
-+static int net1080_check_connect(struct usbnet *dev)
-+{
-+ int retval;
-+ u16 status;
-+ u16 vp;
-+
-+ retval = nc_register_read(dev, REG_STATUS, &vp);
-+ status = vp;
-+ if (retval != 0) {
-+ netdev_dbg(dev->net, "net1080_check_conn read - %d\n", retval);
-+ return retval;
-+ }
-+ if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
-+ return -ENOLINK;
-+ return 0;
-+}
-+
-+static void nc_ensure_sync(struct usbnet *dev)
-+{
-+ if (++dev->frame_errors <= 5)
-+ return;
-+
-+ if (usbnet_write_cmd_async(dev, REQUEST_REGISTER,
-+ USB_DIR_OUT | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE,
-+ USBCTL_FLUSH_THIS |
-+ USBCTL_FLUSH_OTHER,
-+ REG_USBCTL, NULL, 0))
-+ return;
-+
-+ netif_dbg(dev, rx_err, dev->net,
-+ "flush net1080; too many framing errors\n");
-+ dev->frame_errors = 0;
-+}
-+
-+static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct nc_header *header;
-+ struct nc_trailer *trailer;
-+ u16 hdr_len, packet_len;
-+
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ if (!(skb->len & 0x01)) {
-+ netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
-+ skb->len, dev->net->hard_header_len, dev->hard_mtu,
-+ dev->net->mtu);
-+ dev->net->stats.rx_frame_errors++;
-+ nc_ensure_sync(dev);
-+ return 0;
-+ }
-+
-+ header = (struct nc_header *) skb->data;
-+ hdr_len = le16_to_cpup(&header->hdr_len);
-+ packet_len = le16_to_cpup(&header->packet_len);
-+ if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {
-+ dev->net->stats.rx_frame_errors++;
-+ netdev_dbg(dev->net, "packet too big, %d\n", packet_len);
-+ nc_ensure_sync(dev);
-+ return 0;
-+ } else if (hdr_len < MIN_HEADER) {
-+ dev->net->stats.rx_frame_errors++;
-+ netdev_dbg(dev->net, "header too short, %d\n", hdr_len);
-+ nc_ensure_sync(dev);
-+ return 0;
-+ } else if (hdr_len > MIN_HEADER) {
-+ // out of band data for us?
-+ netdev_dbg(dev->net, "header OOB, %d bytes\n", hdr_len - MIN_HEADER);
-+ nc_ensure_sync(dev);
-+ // switch (vendor/product ids) { ... }
-+ }
-+ skb_pull(skb, hdr_len);
-+
-+ trailer = (struct nc_trailer *)
-+ (skb->data + skb->len - sizeof *trailer);
-+ skb_trim(skb, skb->len - sizeof *trailer);
-+
-+ if ((packet_len & 0x01) == 0) {
-+ if (skb->data [packet_len] != PAD_BYTE) {
-+ dev->net->stats.rx_frame_errors++;
-+ netdev_dbg(dev->net, "bad pad\n");
-+ return 0;
-+ }
-+ skb_trim(skb, skb->len - 1);
-+ }
-+ if (skb->len != packet_len) {
-+ dev->net->stats.rx_frame_errors++;
-+ netdev_dbg(dev->net, "bad packet len %d (expected %d)\n",
-+ skb->len, packet_len);
-+ nc_ensure_sync(dev);
-+ return 0;
-+ }
-+ if (header->packet_id != get_unaligned(&trailer->packet_id)) {
-+ dev->net->stats.rx_fifo_errors++;
-+ netdev_dbg(dev->net, "(2+ dropped) rx packet_id mismatch 0x%x 0x%x\n",
-+ le16_to_cpu(header->packet_id),
-+ le16_to_cpu(trailer->packet_id));
-+ return 0;
-+ }
-+#if 0
-+ netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", header->hdr_len,
-+ header->packet_len, header->packet_id);
-+#endif
-+ dev->frame_errors = 0;
-+ return 1;
-+}
-+
-+static struct sk_buff *
-+net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
-+{
-+ struct sk_buff *skb2;
-+ struct nc_header *header = NULL;
-+ struct nc_trailer *trailer = NULL;
-+ int padlen = sizeof (struct nc_trailer);
-+ int len = skb->len;
-+
-+ if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
-+ padlen++;
-+ if (!skb_cloned(skb)) {
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+
-+ if (padlen <= tailroom &&
-+ sizeof(struct nc_header) <= headroom)
-+ /* There's enough head and tail room */
-+ goto encapsulate;
-+
-+ if ((sizeof (struct nc_header) + padlen) <
-+ (headroom + tailroom)) {
-+ /* There's enough total room, so just readjust */
-+ skb->data = memmove(skb->head
-+ + sizeof (struct nc_header),
-+ skb->data, skb->len);
-+ skb_set_tail_pointer(skb, len);
-+ goto encapsulate;
-+ }
-+ }
-+
-+ /* Create a new skb to use with the correct size */
-+ skb2 = skb_copy_expand(skb,
-+ sizeof (struct nc_header),
-+ padlen,
-+ flags);
-+ dev_kfree_skb_any(skb);
-+ if (!skb2)
-+ return skb2;
-+ skb = skb2;
-+
-+encapsulate:
-+ /* header first */
-+ header = (struct nc_header *) skb_push(skb, sizeof *header);
-+ header->hdr_len = cpu_to_le16(sizeof (*header));
-+ header->packet_len = cpu_to_le16(len);
-+ header->packet_id = cpu_to_le16((u16)dev->xid++);
-+
-+ /* maybe pad; then trailer */
-+ if (!((skb->len + sizeof *trailer) & 0x01))
-+ *skb_put(skb, 1) = PAD_BYTE;
-+ trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer);
-+ put_unaligned(header->packet_id, &trailer->packet_id);
-+#if 0
-+ netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n",
-+ header->hdr_len, header->packet_len,
-+ header->packet_id);
-+#endif
-+ return skb;
-+}
-+
-+static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ unsigned extra = sizeof (struct nc_header)
-+ + 1
-+ + sizeof (struct nc_trailer);
-+
-+ dev->net->hard_header_len += extra;
-+ dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
-+ dev->hard_mtu = NC_MAX_PACKET;
-+ return usbnet_get_endpoints (dev, intf);
-+}
-+
-+static const struct driver_info net1080_info = {
-+ .description = "NetChip TurboCONNECT",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC,
-+ .bind = net1080_bind,
-+ .reset = net1080_reset,
-+ .check_connect = net1080_check_connect,
-+ .rx_fixup = net1080_rx_fixup,
-+ .tx_fixup = net1080_tx_fixup,
-+};
-+
-+static const struct usb_device_id products [] = {
-+{
-+ USB_DEVICE(0x0525, 0x1080), // NetChip ref design
-+ .driver_info = (unsigned long) &net1080_info,
-+}, {
-+ USB_DEVICE(0x06D0, 0x0622), // Laplink Gold
-+ .driver_info = (unsigned long) &net1080_info,
-+},
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver net1080_driver = {
-+ .name = "net1080",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(net1080_driver);
-+
-+MODULE_AUTHOR("David Brownell");
-+MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/pegasus.c backports-4.2.6-1/drivers/net/usb/pegasus.c
---- backports-4.2.6-1.org/drivers/net/usb/pegasus.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/pegasus.c 2016-06-28 14:35:17.995307218 +0200
-@@ -0,0 +1,1335 @@
-+/*
-+ * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * ChangeLog:
-+ * .... Most of the time spent on reading sources & docs.
-+ * v0.2.x First official release for the Linux kernel.
-+ * v0.3.0 Beutified and structured, some bugs fixed.
-+ * v0.3.x URBifying bulk requests and bugfixing. First relatively
-+ * stable release. Still can touch device's registers only
-+ * from top-halves.
-+ * v0.4.0 Control messages remained unurbified are now URBs.
-+ * Now we can touch the HW at any time.
-+ * v0.4.9 Control urbs again use process context to wait. Argh...
-+ * Some long standing bugs (enable_net_traffic) fixed.
-+ * Also nasty trick about resubmiting control urb from
-+ * interrupt context used. Please let me know how it
-+ * behaves. Pegasus II support added since this version.
-+ * TODO: suppressing HCD warnings spewage on disconnect.
-+ * v0.4.13 Ethernet address is now set at probe(), not at open()
-+ * time as this seems to break dhcpd.
-+ * v0.5.0 branch to 2.5.x kernels
-+ * v0.5.1 ethtool support added
-+ * v0.5.5 rx socket buffers are in a pool and the their allocation
-+ * is out of the interrupt routine.
-+ * ...
-+ * v0.9.3 simplified [get|set]_register(s), async update registers
-+ * logic revisited, receive skb_pool removed.
-+ */
-+
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/module.h>
-+#include <asm/byteorder.h>
-+#include <asm/uaccess.h>
-+#include "pegasus.h"
-+
-+/*
-+ * Version Information
-+ */
-+#define DRIVER_VERSION "v0.9.3 (2013/04/25)"
-+#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>"
-+#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
-+
-+static const char driver_name[] = "pegasus";
-+
-+#undef PEGASUS_WRITE_EEPROM
-+#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
-+ BMSR_100FULL | BMSR_ANEGCAPABLE)
-+
-+static bool loopback;
-+static bool mii_mode;
-+static char *devid;
-+
-+static struct usb_eth_dev usb_dev_id[] = {
-+#define PEGASUS_DEV(pn, vid, pid, flags) \
-+ {.name = pn, .vendor = vid, .device = pid, .private = flags},
-+#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
-+ PEGASUS_DEV(pn, vid, pid, flags)
-+#include "pegasus.h"
-+#undef PEGASUS_DEV
-+#undef PEGASUS_DEV_CLASS
-+ {NULL, 0, 0, 0},
-+ {NULL, 0, 0, 0}
-+};
-+
-+static struct usb_device_id pegasus_ids[] = {
-+#define PEGASUS_DEV(pn, vid, pid, flags) \
-+ {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid},
-+/*
-+ * The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product
-+ * IDs as the Belkin F5D5050, so we need to teach the pegasus driver to
-+ * ignore adaptors belonging to the "Wireless" class 0xE0. For this one
-+ * case anyway, seeing as the pegasus is for "Wired" adaptors.
-+ */
-+#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
-+ {.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \
-+ .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass},
-+#include "pegasus.h"
-+#undef PEGASUS_DEV
-+#undef PEGASUS_DEV_CLASS
-+ {},
-+ {}
-+};
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_LICENSE("GPL");
-+module_param(loopback, bool, 0);
-+module_param(mii_mode, bool, 0);
-+module_param(devid, charp, 0);
-+MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
-+MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
-+MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'");
-+
-+/* use ethtool to change the level for any given device */
-+static int msg_level = -1;
-+module_param(msg_level, int, 0);
-+MODULE_PARM_DESC(msg_level, "Override default message level");
-+
-+MODULE_DEVICE_TABLE(usb, pegasus_ids);
-+static const struct net_device_ops pegasus_netdev_ops;
-+
-+/*****/
-+
-+static void async_ctrl_callback(struct urb *urb)
-+{
-+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
-+ int status = urb->status;
-+
-+ if (status < 0)
-+ dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
-+ kfree(req);
-+ usb_free_urb(urb);
-+}
-+
-+static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
-+{
-+ int ret;
-+
-+ ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
-+ PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
-+ indx, data, size, 1000);
-+ if (ret < 0)
-+ netif_dbg(pegasus, drv, pegasus->net,
-+ "%s returned %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
-+{
-+ int ret;
-+
-+ ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
-+ PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
-+ indx, data, size, 100);
-+ if (ret < 0)
-+ netif_dbg(pegasus, drv, pegasus->net,
-+ "%s returned %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
-+{
-+ int ret;
-+
-+ ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
-+ PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
-+ indx, &data, 1, 1000);
-+ if (ret < 0)
-+ netif_dbg(pegasus, drv, pegasus->net,
-+ "%s returned %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+static int update_eth_regs_async(pegasus_t *pegasus)
-+{
-+ int ret = -ENOMEM;
-+ struct urb *async_urb;
-+ struct usb_ctrlrequest *req;
-+
-+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
-+ if (req == NULL)
-+ return ret;
-+
-+ async_urb = usb_alloc_urb(0, GFP_ATOMIC);
-+ if (async_urb == NULL) {
-+ kfree(req);
-+ return ret;
-+ }
-+ req->bRequestType = PEGASUS_REQT_WRITE;
-+ req->bRequest = PEGASUS_REQ_SET_REGS;
-+ req->wValue = cpu_to_le16(0);
-+ req->wIndex = cpu_to_le16(EthCtrl0);
-+ req->wLength = cpu_to_le16(3);
-+
-+ usb_fill_control_urb(async_urb, pegasus->usb,
-+ usb_sndctrlpipe(pegasus->usb, 0), (void *)req,
-+ pegasus->eth_regs, 3, async_ctrl_callback, req);
-+
-+ ret = usb_submit_urb(async_urb, GFP_ATOMIC);
-+ if (ret) {
-+ if (ret == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ netif_err(pegasus, drv, pegasus->net,
-+ "%s returned %d\n", __func__, ret);
-+ }
-+ return ret;
-+}
-+
-+static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd)
-+{
-+ int i;
-+ __u8 data[4] = { phy, 0, 0, indx };
-+ __le16 regdi;
-+ int ret = -ETIMEDOUT;
-+
-+ if (cmd & PHY_WRITE) {
-+ __le16 *t = (__le16 *) & data[1];
-+ *t = cpu_to_le16(*regd);
-+ }
-+ set_register(p, PhyCtrl, 0);
-+ set_registers(p, PhyAddr, sizeof(data), data);
-+ set_register(p, PhyCtrl, (indx | cmd));
-+ for (i = 0; i < REG_TIMEOUT; i++) {
-+ ret = get_registers(p, PhyCtrl, 1, data);
-+ if (ret < 0)
-+ goto fail;
-+ if (data[0] & PHY_DONE)
-+ break;
-+ }
-+ if (i >= REG_TIMEOUT)
-+ goto fail;
-+ if (cmd & PHY_READ) {
-+ ret = get_registers(p, PhyData, 2, ®di);
-+ *regd = le16_to_cpu(regdi);
-+ return ret;
-+ }
-+ return 0;
-+fail:
-+ netif_dbg(p, drv, p->net, "%s failed\n", __func__);
-+ return ret;
-+}
-+
-+/* Returns non-negative int on success, error on failure */
-+static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
-+{
-+ return __mii_op(pegasus, phy, indx, regd, PHY_READ);
-+}
-+
-+/* Returns zero on success, error on failure */
-+static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
-+{
-+ return __mii_op(pegasus, phy, indx, regd, PHY_WRITE);
-+}
-+
-+static int mdio_read(struct net_device *dev, int phy_id, int loc)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ u16 res;
-+
-+ read_mii_word(pegasus, phy_id, loc, &res);
-+ return (int)res;
-+}
-+
-+static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ u16 data = val;
-+
-+ write_mii_word(pegasus, phy_id, loc, &data);
-+}
-+
-+static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
-+{
-+ int i;
-+ __u8 tmp;
-+ __le16 retdatai;
-+ int ret;
-+
-+ set_register(pegasus, EpromCtrl, 0);
-+ set_register(pegasus, EpromOffset, index);
-+ set_register(pegasus, EpromCtrl, EPROM_READ);
-+
-+ for (i = 0; i < REG_TIMEOUT; i++) {
-+ ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
-+ if (tmp & EPROM_DONE)
-+ break;
-+ if (ret == -ESHUTDOWN)
-+ goto fail;
-+ }
-+ if (i >= REG_TIMEOUT)
-+ goto fail;
-+
-+ ret = get_registers(pegasus, EpromData, 2, &retdatai);
-+ *retdata = le16_to_cpu(retdatai);
-+ return ret;
-+
-+fail:
-+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
-+ return -ETIMEDOUT;
-+}
-+
-+#ifdef PEGASUS_WRITE_EEPROM
-+static inline void enable_eprom_write(pegasus_t *pegasus)
-+{
-+ __u8 tmp;
-+
-+ get_registers(pegasus, EthCtrl2, 1, &tmp);
-+ set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
-+}
-+
-+static inline void disable_eprom_write(pegasus_t *pegasus)
-+{
-+ __u8 tmp;
-+
-+ get_registers(pegasus, EthCtrl2, 1, &tmp);
-+ set_register(pegasus, EpromCtrl, 0);
-+ set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
-+}
-+
-+static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data)
-+{
-+ int i;
-+ __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE };
-+ int ret;
-+ __le16 le_data = cpu_to_le16(data);
-+
-+ set_registers(pegasus, EpromOffset, 4, d);
-+ enable_eprom_write(pegasus);
-+ set_register(pegasus, EpromOffset, index);
-+ set_registers(pegasus, EpromData, 2, &le_data);
-+ set_register(pegasus, EpromCtrl, EPROM_WRITE);
-+
-+ for (i = 0; i < REG_TIMEOUT; i++) {
-+ ret = get_registers(pegasus, EpromCtrl, 1, &tmp);
-+ if (ret == -ESHUTDOWN)
-+ goto fail;
-+ if (tmp & EPROM_DONE)
-+ break;
-+ }
-+ disable_eprom_write(pegasus);
-+ if (i >= REG_TIMEOUT)
-+ goto fail;
-+
-+ return ret;
-+
-+fail:
-+ netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
-+ return -ETIMEDOUT;
-+}
-+#endif /* PEGASUS_WRITE_EEPROM */
-+
-+static inline void get_node_id(pegasus_t *pegasus, __u8 *id)
-+{
-+ int i;
-+ __u16 w16;
-+
-+ for (i = 0; i < 3; i++) {
-+ read_eprom_word(pegasus, i, &w16);
-+ ((__le16 *) id)[i] = cpu_to_le16(w16);
-+ }
-+}
-+
-+static void set_ethernet_addr(pegasus_t *pegasus)
-+{
-+ __u8 node_id[6];
-+
-+ if (pegasus->features & PEGASUS_II) {
-+ get_registers(pegasus, 0x10, sizeof(node_id), node_id);
-+ } else {
-+ get_node_id(pegasus, node_id);
-+ set_registers(pegasus, EthID, sizeof(node_id), node_id);
-+ }
-+ memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id));
-+}
-+
-+static inline int reset_mac(pegasus_t *pegasus)
-+{
-+ __u8 data = 0x8;
-+ int i;
-+
-+ set_register(pegasus, EthCtrl1, data);
-+ for (i = 0; i < REG_TIMEOUT; i++) {
-+ get_registers(pegasus, EthCtrl1, 1, &data);
-+ if (~data & 0x08) {
-+ if (loopback)
-+ break;
-+ if (mii_mode && (pegasus->features & HAS_HOME_PNA))
-+ set_register(pegasus, Gpio1, 0x34);
-+ else
-+ set_register(pegasus, Gpio1, 0x26);
-+ set_register(pegasus, Gpio0, pegasus->features);
-+ set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);
-+ break;
-+ }
-+ }
-+ if (i == REG_TIMEOUT)
-+ return -ETIMEDOUT;
-+
-+ if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-+ usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-+ set_register(pegasus, Gpio0, 0x24);
-+ set_register(pegasus, Gpio0, 0x26);
-+ }
-+ if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
-+ __u16 auxmode;
-+ read_mii_word(pegasus, 3, 0x1b, &auxmode);
-+ auxmode |= 4;
-+ write_mii_word(pegasus, 3, 0x1b, &auxmode);
-+ }
-+
-+ return 0;
-+}
-+
-+static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
-+{
-+ __u16 linkpart;
-+ __u8 data[4];
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ int ret;
-+
-+ read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart);
-+ data[0] = 0xc9;
-+ data[1] = 0;
-+ if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))
-+ data[1] |= 0x20; /* set full duplex */
-+ if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))
-+ data[1] |= 0x10; /* set 100 Mbps */
-+ if (mii_mode)
-+ data[1] = 0;
-+ data[2] = loopback ? 0x09 : 0x01;
-+
-+ memcpy(pegasus->eth_regs, data, sizeof(data));
-+ ret = set_registers(pegasus, EthCtrl0, 3, data);
-+
-+ if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-+ usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
-+ usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-+ u16 auxmode;
-+ read_mii_word(pegasus, 0, 0x1b, &auxmode);
-+ auxmode |= 4;
-+ write_mii_word(pegasus, 0, 0x1b, &auxmode);
-+ }
-+
-+ return ret;
-+}
-+
-+static void read_bulk_callback(struct urb *urb)
-+{
-+ pegasus_t *pegasus = urb->context;
-+ struct net_device *net;
-+ int rx_status, count = urb->actual_length;
-+ int status = urb->status;
-+ u8 *buf = urb->transfer_buffer;
-+ __u16 pkt_len;
-+
-+ if (!pegasus)
-+ return;
-+
-+ net = pegasus->net;
-+ if (!netif_device_present(net) || !netif_running(net))
-+ return;
-+
-+ switch (status) {
-+ case 0:
-+ break;
-+ case -ETIME:
-+ netif_dbg(pegasus, rx_err, net, "reset MAC\n");
-+ pegasus->flags &= ~PEGASUS_RX_BUSY;
-+ break;
-+ case -EPIPE: /* stall, or disconnect from TT */
-+ /* FIXME schedule work to clear the halt */
-+ netif_warn(pegasus, rx_err, net, "no rx stall recovery\n");
-+ return;
-+ case -ENOENT:
-+ case -ECONNRESET:
-+ case -ESHUTDOWN:
-+ netif_dbg(pegasus, ifdown, net, "rx unlink, %d\n", status);
-+ return;
-+ default:
-+ netif_dbg(pegasus, rx_err, net, "RX status %d\n", status);
-+ goto goon;
-+ }
-+
-+ if (!count || count < 4)
-+ goto goon;
-+
-+ rx_status = buf[count - 2];
-+ if (rx_status & 0x1e) {
-+ netif_dbg(pegasus, rx_err, net,
-+ "RX packet error %x\n", rx_status);
-+ pegasus->stats.rx_errors++;
-+ if (rx_status & 0x06) /* long or runt */
-+ pegasus->stats.rx_length_errors++;
-+ if (rx_status & 0x08)
-+ pegasus->stats.rx_crc_errors++;
-+ if (rx_status & 0x10) /* extra bits */
-+ pegasus->stats.rx_frame_errors++;
-+ goto goon;
-+ }
-+ if (pegasus->chip == 0x8513) {
-+ pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
-+ pkt_len &= 0x0fff;
-+ pegasus->rx_skb->data += 2;
-+ } else {
-+ pkt_len = buf[count - 3] << 8;
-+ pkt_len += buf[count - 4];
-+ pkt_len &= 0xfff;
-+ pkt_len -= 8;
-+ }
-+
-+ /*
-+ * If the packet is unreasonably long, quietly drop it rather than
-+ * kernel panicing by calling skb_put.
-+ */
-+ if (pkt_len > PEGASUS_MTU)
-+ goto goon;
-+
-+ /*
-+ * at this point we are sure pegasus->rx_skb != NULL
-+ * so we go ahead and pass up the packet.
-+ */
-+ skb_put(pegasus->rx_skb, pkt_len);
-+ pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
-+ netif_rx(pegasus->rx_skb);
-+ pegasus->stats.rx_packets++;
-+ pegasus->stats.rx_bytes += pkt_len;
-+
-+ if (pegasus->flags & PEGASUS_UNPLUG)
-+ return;
-+
-+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU,
-+ GFP_ATOMIC);
-+
-+ if (pegasus->rx_skb == NULL)
-+ goto tl_sched;
-+goon:
-+ usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-+ usb_rcvbulkpipe(pegasus->usb, 1),
-+ pegasus->rx_skb->data, PEGASUS_MTU + 8,
-+ read_bulk_callback, pegasus);
-+ rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
-+ if (rx_status == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ else if (rx_status) {
-+ pegasus->flags |= PEGASUS_RX_URB_FAIL;
-+ goto tl_sched;
-+ } else {
-+ pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
-+ }
-+
-+ return;
-+
-+tl_sched:
-+ tasklet_schedule(&pegasus->rx_tl);
-+}
-+
-+static void rx_fixup(unsigned long data)
-+{
-+ pegasus_t *pegasus;
-+ int status;
-+
-+ pegasus = (pegasus_t *) data;
-+ if (pegasus->flags & PEGASUS_UNPLUG)
-+ return;
-+
-+ if (pegasus->flags & PEGASUS_RX_URB_FAIL)
-+ if (pegasus->rx_skb)
-+ goto try_again;
-+ if (pegasus->rx_skb == NULL)
-+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net,
-+ PEGASUS_MTU,
-+ GFP_ATOMIC);
-+ if (pegasus->rx_skb == NULL) {
-+ netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");
-+ tasklet_schedule(&pegasus->rx_tl);
-+ return;
-+ }
-+ usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-+ usb_rcvbulkpipe(pegasus->usb, 1),
-+ pegasus->rx_skb->data, PEGASUS_MTU + 8,
-+ read_bulk_callback, pegasus);
-+try_again:
-+ status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC);
-+ if (status == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ else if (status) {
-+ pegasus->flags |= PEGASUS_RX_URB_FAIL;
-+ tasklet_schedule(&pegasus->rx_tl);
-+ } else {
-+ pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
-+ }
-+}
-+
-+static void write_bulk_callback(struct urb *urb)
-+{
-+ pegasus_t *pegasus = urb->context;
-+ struct net_device *net;
-+ int status = urb->status;
-+
-+ if (!pegasus)
-+ return;
-+
-+ net = pegasus->net;
-+
-+ if (!netif_device_present(net) || !netif_running(net))
-+ return;
-+
-+ switch (status) {
-+ case -EPIPE:
-+ /* FIXME schedule_work() to clear the tx halt */
-+ netif_stop_queue(net);
-+ netif_warn(pegasus, tx_err, net, "no tx stall recovery\n");
-+ return;
-+ case -ENOENT:
-+ case -ECONNRESET:
-+ case -ESHUTDOWN:
-+ netif_dbg(pegasus, ifdown, net, "tx unlink, %d\n", status);
-+ return;
-+ default:
-+ netif_info(pegasus, tx_err, net, "TX status %d\n", status);
-+ /* FALL THROUGH */
-+ case 0:
-+ break;
-+ }
-+
-+ net->trans_start = jiffies; /* prevent tx timeout */
-+ netif_wake_queue(net);
-+}
-+
-+static void intr_callback(struct urb *urb)
-+{
-+ pegasus_t *pegasus = urb->context;
-+ struct net_device *net;
-+ int res, status = urb->status;
-+
-+ if (!pegasus)
-+ return;
-+ net = pegasus->net;
-+
-+ switch (status) {
-+ case 0:
-+ break;
-+ case -ECONNRESET: /* unlink */
-+ case -ENOENT:
-+ case -ESHUTDOWN:
-+ return;
-+ default:
-+ /* some Pegasus-I products report LOTS of data
-+ * toggle errors... avoid log spamming
-+ */
-+ netif_dbg(pegasus, timer, net, "intr status %d\n", status);
-+ }
-+
-+ if (urb->actual_length >= 6) {
-+ u8 *d = urb->transfer_buffer;
-+
-+ /* byte 0 == tx_status1, reg 2B */
-+ if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL
-+ |LATE_COL|JABBER_TIMEOUT)) {
-+ pegasus->stats.tx_errors++;
-+ if (d[0] & TX_UNDERRUN)
-+ pegasus->stats.tx_fifo_errors++;
-+ if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT))
-+ pegasus->stats.tx_aborted_errors++;
-+ if (d[0] & LATE_COL)
-+ pegasus->stats.tx_window_errors++;
-+ }
-+
-+ /* d[5].LINK_STATUS lies on some adapters.
-+ * d[0].NO_CARRIER kicks in only with failed TX.
-+ * ... so monitoring with MII may be safest.
-+ */
-+
-+ /* bytes 3-4 == rx_lostpkt, reg 2E/2F */
-+ pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
-+ }
-+
-+ res = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (res == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ if (res)
-+ netif_err(pegasus, timer, net,
-+ "can't resubmit interrupt urb, %d\n", res);
-+}
-+
-+static void pegasus_tx_timeout(struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+ netif_warn(pegasus, timer, net, "tx timeout\n");
-+ usb_unlink_urb(pegasus->tx_urb);
-+ pegasus->stats.tx_errors++;
-+}
-+
-+static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
-+ struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+ int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
-+ int res;
-+ __u16 l16 = skb->len;
-+
-+ netif_stop_queue(net);
-+
-+ ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
-+ skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len);
-+ usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,
-+ usb_sndbulkpipe(pegasus->usb, 2),
-+ pegasus->tx_buff, count,
-+ write_bulk_callback, pegasus);
-+ if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
-+ netif_warn(pegasus, tx_err, net, "fail tx, %d\n", res);
-+ switch (res) {
-+ case -EPIPE: /* stall, or disconnect from TT */
-+ /* cleanup should already have been scheduled */
-+ break;
-+ case -ENODEV: /* disconnect() upcoming */
-+ case -EPERM:
-+ netif_device_detach(pegasus->net);
-+ break;
-+ default:
-+ pegasus->stats.tx_errors++;
-+ netif_start_queue(net);
-+ }
-+ } else {
-+ pegasus->stats.tx_packets++;
-+ pegasus->stats.tx_bytes += skb->len;
-+ }
-+ dev_kfree_skb(skb);
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
-+{
-+ return &((pegasus_t *) netdev_priv(dev))->stats;
-+}
-+
-+static inline void disable_net_traffic(pegasus_t *pegasus)
-+{
-+ __le16 tmp = cpu_to_le16(0);
-+
-+ set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp);
-+}
-+
-+static inline void get_interrupt_interval(pegasus_t *pegasus)
-+{
-+ u16 data;
-+ u8 interval;
-+
-+ read_eprom_word(pegasus, 4, &data);
-+ interval = data >> 8;
-+ if (pegasus->usb->speed != USB_SPEED_HIGH) {
-+ if (interval < 0x80) {
-+ netif_info(pegasus, timer, pegasus->net,
-+ "intr interval changed from %ums to %ums\n",
-+ interval, 0x80);
-+ interval = 0x80;
-+ data = (data & 0x00FF) | ((u16)interval << 8);
-+#ifdef PEGASUS_WRITE_EEPROM
-+ write_eprom_word(pegasus, 4, data);
-+#endif
-+ }
-+ }
-+ pegasus->intr_interval = interval;
-+}
-+
-+static void set_carrier(struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+ u16 tmp;
-+
-+ if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
-+ return;
-+
-+ if (tmp & BMSR_LSTATUS)
-+ netif_carrier_on(net);
-+ else
-+ netif_carrier_off(net);
-+}
-+
-+static void free_all_urbs(pegasus_t *pegasus)
-+{
-+ usb_free_urb(pegasus->intr_urb);
-+ usb_free_urb(pegasus->tx_urb);
-+ usb_free_urb(pegasus->rx_urb);
-+}
-+
-+static void unlink_all_urbs(pegasus_t *pegasus)
-+{
-+ usb_kill_urb(pegasus->intr_urb);
-+ usb_kill_urb(pegasus->tx_urb);
-+ usb_kill_urb(pegasus->rx_urb);
-+}
-+
-+static int alloc_urbs(pegasus_t *pegasus)
-+{
-+ int res = -ENOMEM;
-+
-+ pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!pegasus->rx_urb) {
-+ return res;
-+ }
-+ pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!pegasus->tx_urb) {
-+ usb_free_urb(pegasus->rx_urb);
-+ return res;
-+ }
-+ pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!pegasus->intr_urb) {
-+ usb_free_urb(pegasus->tx_urb);
-+ usb_free_urb(pegasus->rx_urb);
-+ return res;
-+ }
-+
-+ return 0;
-+}
-+
-+static int pegasus_open(struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+ int res=-ENOMEM;
-+
-+ if (pegasus->rx_skb == NULL)
-+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net,
-+ PEGASUS_MTU,
-+ GFP_KERNEL);
-+ if (!pegasus->rx_skb)
-+ goto exit;
-+
-+ res = set_registers(pegasus, EthID, 6, net->dev_addr);
-+
-+ usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
-+ usb_rcvbulkpipe(pegasus->usb, 1),
-+ pegasus->rx_skb->data, PEGASUS_MTU + 8,
-+ read_bulk_callback, pegasus);
-+ if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) {
-+ if (res == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ netif_dbg(pegasus, ifup, net, "failed rx_urb, %d\n", res);
-+ goto exit;
-+ }
-+
-+ usb_fill_int_urb(pegasus->intr_urb, pegasus->usb,
-+ usb_rcvintpipe(pegasus->usb, 3),
-+ pegasus->intr_buff, sizeof(pegasus->intr_buff),
-+ intr_callback, pegasus, pegasus->intr_interval);
-+ if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) {
-+ if (res == -ENODEV)
-+ netif_device_detach(pegasus->net);
-+ netif_dbg(pegasus, ifup, net, "failed intr_urb, %d\n", res);
-+ usb_kill_urb(pegasus->rx_urb);
-+ goto exit;
-+ }
-+ res = enable_net_traffic(net, pegasus->usb);
-+ if (res < 0) {
-+ netif_dbg(pegasus, ifup, net,
-+ "can't enable_net_traffic() - %d\n", res);
-+ res = -EIO;
-+ usb_kill_urb(pegasus->rx_urb);
-+ usb_kill_urb(pegasus->intr_urb);
-+ goto exit;
-+ }
-+ set_carrier(net);
-+ netif_start_queue(net);
-+ netif_dbg(pegasus, ifup, net, "open\n");
-+ res = 0;
-+exit:
-+ return res;
-+}
-+
-+static int pegasus_close(struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+
-+ netif_stop_queue(net);
-+ if (!(pegasus->flags & PEGASUS_UNPLUG))
-+ disable_net_traffic(pegasus);
-+ tasklet_kill(&pegasus->rx_tl);
-+ unlink_all_urbs(pegasus);
-+
-+ return 0;
-+}
-+
-+static void pegasus_get_drvinfo(struct net_device *dev,
-+ struct ethtool_drvinfo *info)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+
-+ strlcpy(info->driver, driver_name, sizeof(info->driver));
-+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
-+ usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info));
-+}
-+
-+/* also handles three patterns of some kind in hardware */
-+#define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY)
-+
-+static void
-+pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+
-+ wol->supported = WAKE_MAGIC | WAKE_PHY;
-+ wol->wolopts = pegasus->wolopts;
-+}
-+
-+static int
-+pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ u8 reg78 = 0x04;
-+ int ret;
-+
-+ if (wol->wolopts & ~WOL_SUPPORTED)
-+ return -EINVAL;
-+
-+ if (wol->wolopts & WAKE_MAGIC)
-+ reg78 |= 0x80;
-+ if (wol->wolopts & WAKE_PHY)
-+ reg78 |= 0x40;
-+ /* FIXME this 0x10 bit still needs to get set in the chip... */
-+ if (wol->wolopts)
-+ pegasus->eth_regs[0] |= 0x10;
-+ else
-+ pegasus->eth_regs[0] &= ~0x10;
-+ pegasus->wolopts = wol->wolopts;
-+
-+ ret = set_register(pegasus, WakeupControl, reg78);
-+ if (!ret)
-+ ret = device_set_wakeup_enable(&pegasus->usb->dev,
-+ wol->wolopts);
-+ return ret;
-+}
-+
-+static inline void pegasus_reset_wol(struct net_device *dev)
-+{
-+ struct ethtool_wolinfo wol;
-+
-+ memset(&wol, 0, sizeof wol);
-+ (void) pegasus_set_wol(dev, &wol);
-+}
-+
-+static int
-+pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-+{
-+ pegasus_t *pegasus;
-+
-+ pegasus = netdev_priv(dev);
-+ mii_ethtool_gset(&pegasus->mii, ecmd);
-+ return 0;
-+}
-+
-+static int
-+pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ return mii_ethtool_sset(&pegasus->mii, ecmd);
-+}
-+
-+static int pegasus_nway_reset(struct net_device *dev)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ return mii_nway_restart(&pegasus->mii);
-+}
-+
-+static u32 pegasus_get_link(struct net_device *dev)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ return mii_link_ok(&pegasus->mii);
-+}
-+
-+static u32 pegasus_get_msglevel(struct net_device *dev)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ return pegasus->msg_enable;
-+}
-+
-+static void pegasus_set_msglevel(struct net_device *dev, u32 v)
-+{
-+ pegasus_t *pegasus = netdev_priv(dev);
-+ pegasus->msg_enable = v;
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_drvinfo = pegasus_get_drvinfo,
-+ .get_settings = pegasus_get_settings,
-+ .set_settings = pegasus_set_settings,
-+ .nway_reset = pegasus_nway_reset,
-+ .get_link = pegasus_get_link,
-+ .get_msglevel = pegasus_get_msglevel,
-+ .set_msglevel = pegasus_set_msglevel,
-+ .get_wol = pegasus_get_wol,
-+ .set_wol = pegasus_set_wol,
-+};
-+
-+static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ __u16 *data = (__u16 *) &rq->ifr_ifru;
-+ pegasus_t *pegasus = netdev_priv(net);
-+ int res;
-+
-+ switch (cmd) {
-+ case SIOCDEVPRIVATE:
-+ data[0] = pegasus->phy;
-+ case SIOCDEVPRIVATE + 1:
-+ read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]);
-+ res = 0;
-+ break;
-+ case SIOCDEVPRIVATE + 2:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]);
-+ res = 0;
-+ break;
-+ default:
-+ res = -EOPNOTSUPP;
-+ }
-+ return res;
-+}
-+
-+static void pegasus_set_multicast(struct net_device *net)
-+{
-+ pegasus_t *pegasus = netdev_priv(net);
-+
-+ if (net->flags & IFF_PROMISC) {
-+ pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
-+ netif_info(pegasus, link, net, "Promiscuous mode enabled\n");
-+ } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) {
-+ pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
-+ pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
-+ netif_dbg(pegasus, link, net, "set allmulti\n");
-+ } else {
-+ pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
-+ pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
-+ }
-+ update_eth_regs_async(pegasus);
-+}
-+
-+static __u8 mii_phy_probe(pegasus_t *pegasus)
-+{
-+ int i;
-+ __u16 tmp;
-+
-+ for (i = 0; i < 32; i++) {
-+ read_mii_word(pegasus, i, MII_BMSR, &tmp);
-+ if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0)
-+ continue;
-+ else
-+ return i;
-+ }
-+
-+ return 0xff;
-+}
-+
-+static inline void setup_pegasus_II(pegasus_t *pegasus)
-+{
-+ __u8 data = 0xa5;
-+
-+ set_register(pegasus, Reg1d, 0);
-+ set_register(pegasus, Reg7b, 1);
-+ mdelay(100);
-+ if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
-+ set_register(pegasus, Reg7b, 0);
-+ else
-+ set_register(pegasus, Reg7b, 2);
-+
-+ set_register(pegasus, 0x83, data);
-+ get_registers(pegasus, 0x83, 1, &data);
-+
-+ if (data == 0xa5)
-+ pegasus->chip = 0x8513;
-+ else
-+ pegasus->chip = 0;
-+
-+ set_register(pegasus, 0x80, 0xc0);
-+ set_register(pegasus, 0x83, 0xff);
-+ set_register(pegasus, 0x84, 0x01);
-+
-+ if (pegasus->features & HAS_HOME_PNA && mii_mode)
-+ set_register(pegasus, Reg81, 6);
-+ else
-+ set_register(pegasus, Reg81, 2);
-+}
-+
-+
-+static int pegasus_count;
-+static struct workqueue_struct *pegasus_workqueue;
-+#define CARRIER_CHECK_DELAY (2 * HZ)
-+
-+static void check_carrier(struct work_struct *work)
-+{
-+ pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work);
-+ set_carrier(pegasus->net);
-+ if (!(pegasus->flags & PEGASUS_UNPLUG)) {
-+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
-+ CARRIER_CHECK_DELAY);
-+ }
-+}
-+
-+static int pegasus_blacklisted(struct usb_device *udev)
-+{
-+ struct usb_device_descriptor *udd = &udev->descriptor;
-+
-+ /* Special quirk to keep the driver from handling the Belkin Bluetooth
-+ * dongle which happens to have the same ID.
-+ */
-+ if ((udd->idVendor == cpu_to_le16(VENDOR_BELKIN)) &&
-+ (udd->idProduct == cpu_to_le16(0x0121)) &&
-+ (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) &&
-+ (udd->bDeviceProtocol == 1))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/* we rely on probe() and remove() being serialized so we
-+ * don't need extra locking on pegasus_count.
-+ */
-+static void pegasus_dec_workqueue(void)
-+{
-+ pegasus_count--;
-+ if (pegasus_count == 0) {
-+ destroy_workqueue(pegasus_workqueue);
-+ pegasus_workqueue = NULL;
-+ }
-+}
-+
-+static int pegasus_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_device *dev = interface_to_usbdev(intf);
-+ struct net_device *net;
-+ pegasus_t *pegasus;
-+ int dev_index = id - pegasus_ids;
-+ int res = -ENOMEM;
-+
-+ if (pegasus_blacklisted(dev))
-+ return -ENODEV;
-+
-+ if (pegasus_count == 0) {
-+ pegasus_workqueue = create_singlethread_workqueue("pegasus");
-+ if (!pegasus_workqueue)
-+ return -ENOMEM;
-+ }
-+ pegasus_count++;
-+
-+ net = alloc_etherdev(sizeof(struct pegasus));
-+ if (!net)
-+ goto out;
-+
-+ pegasus = netdev_priv(net);
-+ pegasus->dev_index = dev_index;
-+
-+ res = alloc_urbs(pegasus);
-+ if (res < 0) {
-+ dev_err(&intf->dev, "can't allocate %s\n", "urbs");
-+ goto out1;
-+ }
-+
-+ tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
-+
-+ INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier);
-+
-+ pegasus->intf = intf;
-+ pegasus->usb = dev;
-+ pegasus->net = net;
-+
-+
-+ net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
-+ net->netdev_ops = &pegasus_netdev_ops;
-+ net->ethtool_ops = &ops;
-+ pegasus->mii.dev = net;
-+ pegasus->mii.mdio_read = mdio_read;
-+ pegasus->mii.mdio_write = mdio_write;
-+ pegasus->mii.phy_id_mask = 0x1f;
-+ pegasus->mii.reg_num_mask = 0x1f;
-+ pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
-+ | NETIF_MSG_PROBE | NETIF_MSG_LINK);
-+
-+ pegasus->features = usb_dev_id[dev_index].private;
-+ get_interrupt_interval(pegasus);
-+ if (reset_mac(pegasus)) {
-+ dev_err(&intf->dev, "can't reset MAC\n");
-+ res = -EIO;
-+ goto out2;
-+ }
-+ set_ethernet_addr(pegasus);
-+ if (pegasus->features & PEGASUS_II) {
-+ dev_info(&intf->dev, "setup Pegasus II specific registers\n");
-+ setup_pegasus_II(pegasus);
-+ }
-+ pegasus->phy = mii_phy_probe(pegasus);
-+ if (pegasus->phy == 0xff) {
-+ dev_warn(&intf->dev, "can't locate MII phy, using default\n");
-+ pegasus->phy = 1;
-+ }
-+ pegasus->mii.phy_id = pegasus->phy;
-+ usb_set_intfdata(intf, pegasus);
-+ SET_NETDEV_DEV(net, &intf->dev);
-+ pegasus_reset_wol(net);
-+ res = register_netdev(net);
-+ if (res)
-+ goto out3;
-+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
-+ CARRIER_CHECK_DELAY);
-+ dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
-+ usb_dev_id[dev_index].name, net->dev_addr);
-+ return 0;
-+
-+out3:
-+ usb_set_intfdata(intf, NULL);
-+out2:
-+ free_all_urbs(pegasus);
-+out1:
-+ free_netdev(net);
-+out:
-+ pegasus_dec_workqueue();
-+ return res;
-+}
-+
-+static void pegasus_disconnect(struct usb_interface *intf)
-+{
-+ struct pegasus *pegasus = usb_get_intfdata(intf);
-+
-+ usb_set_intfdata(intf, NULL);
-+ if (!pegasus) {
-+ dev_dbg(&intf->dev, "unregistering non-bound device?\n");
-+ return;
-+ }
-+
-+ pegasus->flags |= PEGASUS_UNPLUG;
-+ cancel_delayed_work(&pegasus->carrier_check);
-+ unregister_netdev(pegasus->net);
-+ unlink_all_urbs(pegasus);
-+ free_all_urbs(pegasus);
-+ if (pegasus->rx_skb != NULL) {
-+ dev_kfree_skb(pegasus->rx_skb);
-+ pegasus->rx_skb = NULL;
-+ }
-+ free_netdev(pegasus->net);
-+ pegasus_dec_workqueue();
-+}
-+
-+static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct pegasus *pegasus = usb_get_intfdata(intf);
-+
-+ netif_device_detach(pegasus->net);
-+ cancel_delayed_work(&pegasus->carrier_check);
-+ if (netif_running(pegasus->net)) {
-+ usb_kill_urb(pegasus->rx_urb);
-+ usb_kill_urb(pegasus->intr_urb);
-+ }
-+ return 0;
-+}
-+
-+static int pegasus_resume(struct usb_interface *intf)
-+{
-+ struct pegasus *pegasus = usb_get_intfdata(intf);
-+
-+ netif_device_attach(pegasus->net);
-+ if (netif_running(pegasus->net)) {
-+ pegasus->rx_urb->status = 0;
-+ pegasus->rx_urb->actual_length = 0;
-+ read_bulk_callback(pegasus->rx_urb);
-+
-+ pegasus->intr_urb->status = 0;
-+ pegasus->intr_urb->actual_length = 0;
-+ intr_callback(pegasus->intr_urb);
-+ }
-+ queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
-+ CARRIER_CHECK_DELAY);
-+ return 0;
-+}
-+
-+static const struct net_device_ops pegasus_netdev_ops = {
-+ .ndo_open = pegasus_open,
-+ .ndo_stop = pegasus_close,
-+ .ndo_do_ioctl = pegasus_ioctl,
-+ .ndo_start_xmit = pegasus_start_xmit,
-+ .ndo_set_rx_mode = pegasus_set_multicast,
-+ .ndo_get_stats = pegasus_netdev_stats,
-+ .ndo_tx_timeout = pegasus_tx_timeout,
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+};
-+
-+static struct usb_driver pegasus_driver = {
-+ .name = driver_name,
-+ .probe = pegasus_probe,
-+ .disconnect = pegasus_disconnect,
-+ .id_table = pegasus_ids,
-+ .suspend = pegasus_suspend,
-+ .resume = pegasus_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+static void __init parse_id(char *id)
-+{
-+ unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
-+ char *token, *name = NULL;
-+
-+ if ((token = strsep(&id, ":")) != NULL)
-+ name = token;
-+ /* name now points to a null terminated string*/
-+ if ((token = strsep(&id, ":")) != NULL)
-+ vendor_id = simple_strtoul(token, NULL, 16);
-+ if ((token = strsep(&id, ":")) != NULL)
-+ device_id = simple_strtoul(token, NULL, 16);
-+ flags = simple_strtoul(id, NULL, 16);
-+ pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n",
-+ driver_name, name, vendor_id, device_id, flags);
-+
-+ if (vendor_id > 0x10000 || vendor_id == 0)
-+ return;
-+ if (device_id > 0x10000 || device_id == 0)
-+ return;
-+
-+ for (i = 0; usb_dev_id[i].name; i++);
-+ usb_dev_id[i].name = name;
-+ usb_dev_id[i].vendor = vendor_id;
-+ usb_dev_id[i].device = device_id;
-+ usb_dev_id[i].private = flags;
-+ pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-+ pegasus_ids[i].idVendor = vendor_id;
-+ pegasus_ids[i].idProduct = device_id;
-+}
-+
-+static int __init pegasus_init(void)
-+{
-+ pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
-+ if (devid)
-+ parse_id(devid);
-+ return usb_register(&pegasus_driver);
-+}
-+
-+static void __exit pegasus_exit(void)
-+{
-+ usb_deregister(&pegasus_driver);
-+}
-+
-+module_init(pegasus_init);
-+module_exit(pegasus_exit);
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/pegasus.h backports-4.2.6-1/drivers/net/usb/pegasus.h
---- backports-4.2.6-1.org/drivers/net/usb/pegasus.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/pegasus.h 2016-06-28 14:35:17.998640551 +0200
-@@ -0,0 +1,308 @@
-+/*
-+ * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com)
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ */
-+
-+
-+#ifndef PEGASUS_DEV
-+
-+#define PEGASUS_II 0x80000000
-+#define HAS_HOME_PNA 0x40000000
-+
-+#define PEGASUS_MTU 1536
-+
-+#define EPROM_WRITE 0x01
-+#define EPROM_READ 0x02
-+#define EPROM_DONE 0x04
-+#define EPROM_WR_ENABLE 0x10
-+#define EPROM_LOAD 0x20
-+
-+#define PHY_DONE 0x80
-+#define PHY_READ 0x40
-+#define PHY_WRITE 0x20
-+#define DEFAULT_GPIO_RESET 0x24
-+#define DEFAULT_GPIO_SET 0x26
-+
-+#define PEGASUS_PRESENT 0x00000001
-+#define PEGASUS_TX_BUSY 0x00000004
-+#define PEGASUS_RX_BUSY 0x00000008
-+#define CTRL_URB_RUNNING 0x00000010
-+#define CTRL_URB_SLEEP 0x00000020
-+#define PEGASUS_UNPLUG 0x00000040
-+#define PEGASUS_RX_URB_FAIL 0x00000080
-+
-+#define RX_MULTICAST 2
-+#define RX_PROMISCUOUS 4
-+
-+#define REG_TIMEOUT (HZ)
-+#define PEGASUS_TX_TIMEOUT (HZ*10)
-+
-+#define TX_UNDERRUN 0x80
-+#define EXCESSIVE_COL 0x40
-+#define LATE_COL 0x20
-+#define NO_CARRIER 0x10
-+#define LOSS_CARRIER 0x08
-+#define JABBER_TIMEOUT 0x04
-+
-+#define LINK_STATUS 0x01
-+
-+#define PEGASUS_REQT_READ 0xc0
-+#define PEGASUS_REQT_WRITE 0x40
-+#define PEGASUS_REQ_GET_REGS 0xf0
-+#define PEGASUS_REQ_SET_REGS 0xf1
-+#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS
-+
-+enum pegasus_registers {
-+ EthCtrl0 = 0,
-+ EthCtrl1 = 1,
-+ EthCtrl2 = 2,
-+ EthID = 0x10,
-+ Reg1d = 0x1d,
-+ EpromOffset = 0x20,
-+ EpromData = 0x21, /* 0x21 low, 0x22 high byte */
-+ EpromCtrl = 0x23,
-+ PhyAddr = 0x25,
-+ PhyData = 0x26, /* 0x26 low, 0x27 high byte */
-+ PhyCtrl = 0x28,
-+ UsbStst = 0x2a,
-+ EthTxStat0 = 0x2b,
-+ EthTxStat1 = 0x2c,
-+ EthRxStat = 0x2d,
-+ WakeupControl = 0x78,
-+ Reg7b = 0x7b,
-+ Gpio0 = 0x7e,
-+ Gpio1 = 0x7f,
-+ Reg81 = 0x81,
-+};
-+
-+
-+typedef struct pegasus {
-+ struct usb_device *usb;
-+ struct usb_interface *intf;
-+ struct net_device *net;
-+ struct net_device_stats stats;
-+ struct mii_if_info mii;
-+ unsigned flags;
-+ unsigned features;
-+ u32 msg_enable;
-+ u32 wolopts;
-+ int dev_index;
-+ int intr_interval;
-+ struct tasklet_struct rx_tl;
-+ struct delayed_work carrier_check;
-+ struct urb *rx_urb, *tx_urb, *intr_urb;
-+ struct sk_buff *rx_skb;
-+ int chip;
-+ unsigned char intr_buff[8];
-+ __u8 tx_buff[PEGASUS_MTU];
-+ __u8 eth_regs[4];
-+ __u8 phy;
-+ __u8 gpio_res;
-+} pegasus_t;
-+
-+
-+struct usb_eth_dev {
-+ char *name;
-+ __u16 vendor;
-+ __u16 device;
-+ __u32 private; /* LSB is gpio reset value */
-+};
-+
-+#define VENDOR_3COM 0x0506
-+#define VENDOR_ABOCOM 0x07b8
-+#define VENDOR_ACCTON 0x083a
-+#define VENDOR_ADMTEK 0x07a6
-+#define VENDOR_AEILAB 0x3334
-+#define VENDOR_ALLIEDTEL 0x07c9
-+#define VENDOR_ATEN 0x0557
-+#define VENDOR_BELKIN 0x050d
-+#define VENDOR_BILLIONTON 0x08dd
-+#define VENDOR_COMPAQ 0x049f
-+#define VENDOR_COREGA 0x07aa
-+#define VENDOR_DLINK 0x2001
-+#define VENDOR_ELCON 0x0db7
-+#define VENDOR_ELECOM 0x056e
-+#define VENDOR_ELSA 0x05cc
-+#define VENDOR_GIGABYTE 0x1044
-+#define VENDOR_HAWKING 0x0e66
-+#define VENDOR_HP 0x03f0
-+#define VENDOR_IODATA 0x04bb
-+#define VENDOR_KINGSTON 0x0951
-+#define VENDOR_LANEED 0x056e
-+#define VENDOR_LINKSYS 0x066b
-+#define VENDOR_LINKSYS2 0x077b
-+#define VENDOR_MELCO 0x0411
-+#define VENDOR_MICROSOFT 0x045e
-+#define VENDOR_MOBILITY 0x1342
-+#define VENDOR_NETGEAR 0x0846
-+#define VENDOR_OCT 0x0b39
-+#define VENDOR_SMARTBRIDGES 0x08d1
-+#define VENDOR_SMC 0x0707
-+#define VENDOR_SOHOWARE 0x15e8
-+#define VENDOR_SIEMENS 0x067c
-+
-+
-+#else /* PEGASUS_DEV */
-+
-+PEGASUS_DEV("3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
-+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
-+ VENDOR_ADMTEK, 0x8511,
-+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
-+PEGASUS_DEV("ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
-+ VENDOR_ADMTEK, 0x8513,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet",
-+ VENDOR_ADMTEK, 0x8515,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
-+ VENDOR_ADMTEK, 0x0986,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("AN986A USB MAC", VENDOR_ADMTEK, 1986,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+/*
-+ * Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors
-+ * with the same product IDs by checking the device class too.
-+ */
-+PEGASUS_DEV_CLASS("Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("D-Link DSB-650", VENDOR_DLINK, 0xabc1,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
-+ DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA)
-+PEGASUS_DEV("ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
-+ DEFAULT_GPIO_RESET | HAS_HOME_PNA)
-+PEGASUS_DEV("Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("Microsoft MN-110", VENDOR_MICROSOFT, 0x007a,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("OCT Inc.", VENDOR_OCT, 0x0109,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("OCT USB TO Ethernet", VENDOR_OCT, 0x0901,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
-+ DEFAULT_GPIO_RESET)
-+PEGASUS_DEV("SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
-+ DEFAULT_GPIO_RESET | PEGASUS_II)
-+
-+
-+#endif /* PEGASUS_DEV */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/plusb.c backports-4.2.6-1/drivers/net/usb/plusb.c
---- backports-4.2.6-1.org/drivers/net/usb/plusb.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/plusb.c 2016-06-28 14:35:17.998640551 +0200
-@@ -0,0 +1,162 @@
-+/*
-+ * PL-2301/2302 USB host-to-host link cables
-+ * Copyright (C) 2000-2005 by David Brownell
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+// #define DEBUG // error path messages, extra info
-+// #define VERBOSE // more; success messages
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/usb/usbnet.h>
-+
-+
-+/*
-+ * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/
-+ *
-+ * The protocol and handshaking used here should be bug-compatible
-+ * with the Linux 2.2 "plusb" driver, by Deti Fliegl.
-+ *
-+ * HEADS UP: this handshaking isn't all that robust. This driver
-+ * gets confused easily if you unplug one end of the cable then
-+ * try to connect it again; you'll need to restart both ends. The
-+ * "naplink" software (used by some PlayStation/2 deveopers) does
-+ * the handshaking much better! Also, sometimes this hardware
-+ * seems to get wedged under load. Prolific docs are weak, and
-+ * don't identify differences between PL2301 and PL2302, much less
-+ * anything to explain the different PL2302 versions observed.
-+ *
-+ * NOTE: pl2501 has several modes, including pl2301 and pl2302
-+ * compatibility. Some docs suggest the difference between 2301
-+ * and 2302 is only to make MS-Windows use a different driver...
-+ *
-+ * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on
-+ * this chip are as usual incomplete about what control messages
-+ * are supported.
-+ */
-+
-+/*
-+ * Bits 0-4 can be used for software handshaking; they're set from
-+ * one end, cleared from the other, "read" with the interrupt byte.
-+ */
-+#define PL_S_EN (1<<7) /* (feature only) suspend enable */
-+/* reserved bit -- rx ready (6) ? */
-+#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */
-+#define PL_RESET_OUT (1<<4) /* reset output pipe */
-+#define PL_RESET_IN (1<<3) /* reset input pipe */
-+#define PL_TX_C (1<<2) /* transmission complete */
-+#define PL_TX_REQ (1<<1) /* transmission received */
-+#define PL_PEER_E (1<<0) /* peer exists */
-+
-+static inline int
-+pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
-+{
-+ return usbnet_read_cmd(dev, req,
-+ USB_DIR_IN | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE,
-+ val, index, NULL, 0);
-+}
-+
-+static inline int
-+pl_clear_QuickLink_features(struct usbnet *dev, int val)
-+{
-+ return pl_vendor_req(dev, 1, (u8) val, 0);
-+}
-+
-+static inline int
-+pl_set_QuickLink_features(struct usbnet *dev, int val)
-+{
-+ return pl_vendor_req(dev, 3, (u8) val, 0);
-+}
-+
-+static int pl_reset(struct usbnet *dev)
-+{
-+ int status;
-+
-+ /* some units seem to need this reset, others reject it utterly.
-+ * FIXME be more like "naplink" or windows drivers.
-+ */
-+ status = pl_set_QuickLink_features(dev,
-+ PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
-+ if (status != 0 && netif_msg_probe(dev))
-+ netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status);
-+ return 0;
-+}
-+
-+static const struct driver_info prolific_info = {
-+ .description = "Prolific PL-2301/PL-2302/PL-25A1",
-+ .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT,
-+ /* some PL-2302 versions seem to fail usb_set_interface() */
-+ .reset = pl_reset,
-+};
-+
-+
-+/*-------------------------------------------------------------------------*/
-+
-+/*
-+ * Proilific's name won't normally be on the cables, and
-+ * may not be on the device.
-+ */
-+
-+static const struct usb_device_id products [] = {
-+
-+/* full speed cables */
-+{
-+ USB_DEVICE(0x067b, 0x0000), // PL-2301
-+ .driver_info = (unsigned long) &prolific_info,
-+}, {
-+ USB_DEVICE(0x067b, 0x0001), // PL-2302
-+ .driver_info = (unsigned long) &prolific_info,
-+},
-+
-+/* high speed cables */
-+{
-+ USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */
-+ .driver_info = (unsigned long) &prolific_info,
-+}, {
-+ USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */
-+ .driver_info = (unsigned long) &prolific_info,
-+}, {
-+ USB_DEVICE(0x3923, 0x7825), /* National Instruments USB
-+ * Host-to-Host Cable
-+ */
-+ .driver_info = (unsigned long) &prolific_info,
-+},
-+
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver plusb_driver = {
-+ .name = "plusb",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(plusb_driver);
-+
-+MODULE_AUTHOR("David Brownell");
-+MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/r8152.c backports-4.2.6-1/drivers/net/usb/r8152.c
---- backports-4.2.6-1.org/drivers/net/usb/r8152.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/r8152.c 2016-06-28 14:45:32.005250978 +0200
-@@ -0,0 +1,2856 @@
-+/*
-+ * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/signal.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/mii.h>
-+#include <linux/ethtool.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/if_vlan.h>
-+#include <linux/uaccess.h>
-+#include <linux/list.h>
-+#include <linux/ip.h>
-+#include <linux/ipv6.h>
-+
-+/* Version Information */
-+#define DRIVER_VERSION "v1.04.0 (2014/01/15)"
-+#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
-+#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
-+#define MODULENAME "r8152"
-+
-+#define R8152_PHY_ID 32
-+
-+#define PLA_IDR 0xc000
-+#define PLA_RCR 0xc010
-+#define PLA_RMS 0xc016
-+#define PLA_RXFIFO_CTRL0 0xc0a0
-+#define PLA_RXFIFO_CTRL1 0xc0a4
-+#define PLA_RXFIFO_CTRL2 0xc0a8
-+#define PLA_FMC 0xc0b4
-+#define PLA_CFG_WOL 0xc0b6
-+#define PLA_TEREDO_CFG 0xc0bc
-+#define PLA_MAR 0xcd00
-+#define PLA_BACKUP 0xd000
-+#define PAL_BDC_CR 0xd1a0
-+#define PLA_TEREDO_TIMER 0xd2cc
-+#define PLA_REALWOW_TIMER 0xd2e8
-+#define PLA_LEDSEL 0xdd90
-+#define PLA_LED_FEATURE 0xdd92
-+#define PLA_PHYAR 0xde00
-+#define PLA_BOOT_CTRL 0xe004
-+#define PLA_GPHY_INTR_IMR 0xe022
-+#define PLA_EEE_CR 0xe040
-+#define PLA_EEEP_CR 0xe080
-+#define PLA_MAC_PWR_CTRL 0xe0c0
-+#define PLA_MAC_PWR_CTRL2 0xe0ca
-+#define PLA_MAC_PWR_CTRL3 0xe0cc
-+#define PLA_MAC_PWR_CTRL4 0xe0ce
-+#define PLA_WDT6_CTRL 0xe428
-+#define PLA_TCR0 0xe610
-+#define PLA_TCR1 0xe612
-+#define PLA_TXFIFO_CTRL 0xe618
-+#define PLA_RSTTELLY 0xe800
-+#define PLA_CR 0xe813
-+#define PLA_CRWECR 0xe81c
-+#define PLA_CONFIG5 0xe822
-+#define PLA_PHY_PWR 0xe84c
-+#define PLA_OOB_CTRL 0xe84f
-+#define PLA_CPCR 0xe854
-+#define PLA_MISC_0 0xe858
-+#define PLA_MISC_1 0xe85a
-+#define PLA_OCP_GPHY_BASE 0xe86c
-+#define PLA_TELLYCNT 0xe890
-+#define PLA_SFF_STS_7 0xe8de
-+#define PLA_PHYSTATUS 0xe908
-+#define PLA_BP_BA 0xfc26
-+#define PLA_BP_0 0xfc28
-+#define PLA_BP_1 0xfc2a
-+#define PLA_BP_2 0xfc2c
-+#define PLA_BP_3 0xfc2e
-+#define PLA_BP_4 0xfc30
-+#define PLA_BP_5 0xfc32
-+#define PLA_BP_6 0xfc34
-+#define PLA_BP_7 0xfc36
-+#define PLA_BP_EN 0xfc38
-+
-+#define USB_U2P3_CTRL 0xb460
-+#define USB_DEV_STAT 0xb808
-+#define USB_USB_CTRL 0xd406
-+#define USB_PHY_CTRL 0xd408
-+#define USB_TX_AGG 0xd40a
-+#define USB_RX_BUF_TH 0xd40c
-+#define USB_USB_TIMER 0xd428
-+#define USB_RX_EARLY_AGG 0xd42c
-+#define USB_PM_CTRL_STATUS 0xd432
-+#define USB_TX_DMA 0xd434
-+#define USB_TOLERANCE 0xd490
-+#define USB_LPM_CTRL 0xd41a
-+#define USB_UPS_CTRL 0xd800
-+#define USB_MISC_0 0xd81a
-+#define USB_POWER_CUT 0xd80a
-+#define USB_AFE_CTRL2 0xd824
-+#define USB_WDT11_CTRL 0xe43c
-+#define USB_BP_BA 0xfc26
-+#define USB_BP_0 0xfc28
-+#define USB_BP_1 0xfc2a
-+#define USB_BP_2 0xfc2c
-+#define USB_BP_3 0xfc2e
-+#define USB_BP_4 0xfc30
-+#define USB_BP_5 0xfc32
-+#define USB_BP_6 0xfc34
-+#define USB_BP_7 0xfc36
-+#define USB_BP_EN 0xfc38
-+
-+/* OCP Registers */
-+#define OCP_ALDPS_CONFIG 0x2010
-+#define OCP_EEE_CONFIG1 0x2080
-+#define OCP_EEE_CONFIG2 0x2092
-+#define OCP_EEE_CONFIG3 0x2094
-+#define OCP_BASE_MII 0xa400
-+#define OCP_EEE_AR 0xa41a
-+#define OCP_EEE_DATA 0xa41c
-+#define OCP_PHY_STATUS 0xa420
-+#define OCP_POWER_CFG 0xa430
-+#define OCP_EEE_CFG 0xa432
-+#define OCP_SRAM_ADDR 0xa436
-+#define OCP_SRAM_DATA 0xa438
-+#define OCP_DOWN_SPEED 0xa442
-+#define OCP_EEE_CFG2 0xa5d0
-+#define OCP_ADC_CFG 0xbc06
-+
-+/* SRAM Register */
-+#define SRAM_LPF_CFG 0x8012
-+#define SRAM_10M_AMP1 0x8080
-+#define SRAM_10M_AMP2 0x8082
-+#define SRAM_IMPEDANCE 0x8084
-+
-+/* PLA_RCR */
-+#define RCR_AAP 0x00000001
-+#define RCR_APM 0x00000002
-+#define RCR_AM 0x00000004
-+#define RCR_AB 0x00000008
-+#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
-+
-+/* PLA_RXFIFO_CTRL0 */
-+#define RXFIFO_THR1_NORMAL 0x00080002
-+#define RXFIFO_THR1_OOB 0x01800003
-+
-+/* PLA_RXFIFO_CTRL1 */
-+#define RXFIFO_THR2_FULL 0x00000060
-+#define RXFIFO_THR2_HIGH 0x00000038
-+#define RXFIFO_THR2_OOB 0x0000004a
-+#define RXFIFO_THR2_NORMAL 0x00a0
-+
-+/* PLA_RXFIFO_CTRL2 */
-+#define RXFIFO_THR3_FULL 0x00000078
-+#define RXFIFO_THR3_HIGH 0x00000048
-+#define RXFIFO_THR3_OOB 0x0000005a
-+#define RXFIFO_THR3_NORMAL 0x0110
-+
-+/* PLA_TXFIFO_CTRL */
-+#define TXFIFO_THR_NORMAL 0x00400008
-+#define TXFIFO_THR_NORMAL2 0x01000008
-+
-+/* PLA_FMC */
-+#define FMC_FCR_MCU_EN 0x0001
-+
-+/* PLA_EEEP_CR */
-+#define EEEP_CR_EEEP_TX 0x0002
-+
-+/* PLA_WDT6_CTRL */
-+#define WDT6_SET_MODE 0x0010
-+
-+/* PLA_TCR0 */
-+#define TCR0_TX_EMPTY 0x0800
-+#define TCR0_AUTO_FIFO 0x0080
-+
-+/* PLA_TCR1 */
-+#define VERSION_MASK 0x7cf0
-+
-+/* PLA_CR */
-+#define CR_RST 0x10
-+#define CR_RE 0x08
-+#define CR_TE 0x04
-+
-+/* PLA_CRWECR */
-+#define CRWECR_NORAML 0x00
-+#define CRWECR_CONFIG 0xc0
-+
-+/* PLA_OOB_CTRL */
-+#define NOW_IS_OOB 0x80
-+#define TXFIFO_EMPTY 0x20
-+#define RXFIFO_EMPTY 0x10
-+#define LINK_LIST_READY 0x02
-+#define DIS_MCU_CLROOB 0x01
-+#define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY)
-+
-+/* PLA_MISC_1 */
-+#define RXDY_GATED_EN 0x0008
-+
-+/* PLA_SFF_STS_7 */
-+#define RE_INIT_LL 0x8000
-+#define MCU_BORW_EN 0x4000
-+
-+/* PLA_CPCR */
-+#define CPCR_RX_VLAN 0x0040
-+
-+/* PLA_CFG_WOL */
-+#define MAGIC_EN 0x0001
-+
-+/* PLA_TEREDO_CFG */
-+#define TEREDO_SEL 0x8000
-+#define TEREDO_WAKE_MASK 0x7f00
-+#define TEREDO_RS_EVENT_MASK 0x00fe
-+#define OOB_TEREDO_EN 0x0001
-+
-+/* PAL_BDC_CR */
-+#define ALDPS_PROXY_MODE 0x0001
-+
-+/* PLA_CONFIG5 */
-+#define LAN_WAKE_EN 0x0002
-+
-+/* PLA_LED_FEATURE */
-+#define LED_MODE_MASK 0x0700
-+
-+/* PLA_PHY_PWR */
-+#define TX_10M_IDLE_EN 0x0080
-+#define PFM_PWM_SWITCH 0x0040
-+
-+/* PLA_MAC_PWR_CTRL */
-+#define D3_CLK_GATED_EN 0x00004000
-+#define MCU_CLK_RATIO 0x07010f07
-+#define MCU_CLK_RATIO_MASK 0x0f0f0f0f
-+#define ALDPS_SPDWN_RATIO 0x0f87
-+
-+/* PLA_MAC_PWR_CTRL2 */
-+#define EEE_SPDWN_RATIO 0x8007
-+
-+/* PLA_MAC_PWR_CTRL3 */
-+#define PKT_AVAIL_SPDWN_EN 0x0100
-+#define SUSPEND_SPDWN_EN 0x0004
-+#define U1U2_SPDWN_EN 0x0002
-+#define L1_SPDWN_EN 0x0001
-+
-+/* PLA_MAC_PWR_CTRL4 */
-+#define PWRSAVE_SPDWN_EN 0x1000
-+#define RXDV_SPDWN_EN 0x0800
-+#define TX10MIDLE_EN 0x0100
-+#define TP100_SPDWN_EN 0x0020
-+#define TP500_SPDWN_EN 0x0010
-+#define TP1000_SPDWN_EN 0x0008
-+#define EEE_SPDWN_EN 0x0001
-+
-+/* PLA_GPHY_INTR_IMR */
-+#define GPHY_STS_MSK 0x0001
-+#define SPEED_DOWN_MSK 0x0002
-+#define SPDWN_RXDV_MSK 0x0004
-+#define SPDWN_LINKCHG_MSK 0x0008
-+
-+/* PLA_PHYAR */
-+#define PHYAR_FLAG 0x80000000
-+
-+/* PLA_EEE_CR */
-+#define EEE_RX_EN 0x0001
-+#define EEE_TX_EN 0x0002
-+
-+/* PLA_BOOT_CTRL */
-+#define AUTOLOAD_DONE 0x0002
-+
-+/* USB_DEV_STAT */
-+#define STAT_SPEED_MASK 0x0006
-+#define STAT_SPEED_HIGH 0x0000
-+#define STAT_SPEED_FULL 0x0001
-+
-+/* USB_TX_AGG */
-+#define TX_AGG_MAX_THRESHOLD 0x03
-+
-+/* USB_RX_BUF_TH */
-+#define RX_THR_SUPPER 0x0c350180
-+#define RX_THR_HIGH 0x7a120180
-+#define RX_THR_SLOW 0xffff0180
-+
-+/* USB_TX_DMA */
-+#define TEST_MODE_DISABLE 0x00000001
-+#define TX_SIZE_ADJUST1 0x00000100
-+
-+/* USB_UPS_CTRL */
-+#define POWER_CUT 0x0100
-+
-+/* USB_PM_CTRL_STATUS */
-+#define RESUME_INDICATE 0x0001
-+
-+/* USB_USB_CTRL */
-+#define RX_AGG_DISABLE 0x0010
-+
-+/* USB_U2P3_CTRL */
-+#define U2P3_ENABLE 0x0001
-+
-+/* USB_POWER_CUT */
-+#define PWR_EN 0x0001
-+#define PHASE2_EN 0x0008
-+
-+/* USB_MISC_0 */
-+#define PCUT_STATUS 0x0001
-+
-+/* USB_RX_EARLY_AGG */
-+#define EARLY_AGG_SUPPER 0x0e832981
-+#define EARLY_AGG_HIGH 0x0e837a12
-+#define EARLY_AGG_SLOW 0x0e83ffff
-+
-+/* USB_WDT11_CTRL */
-+#define TIMER11_EN 0x0001
-+
-+/* USB_LPM_CTRL */
-+#define LPM_TIMER_MASK 0x0c
-+#define LPM_TIMER_500MS 0x04 /* 500 ms */
-+#define LPM_TIMER_500US 0x0c /* 500 us */
-+
-+/* USB_AFE_CTRL2 */
-+#define SEN_VAL_MASK 0xf800
-+#define SEN_VAL_NORMAL 0xa000
-+#define SEL_RXIDLE 0x0100
-+
-+/* OCP_ALDPS_CONFIG */
-+#define ENPWRSAVE 0x8000
-+#define ENPDNPS 0x0200
-+#define LINKENA 0x0100
-+#define DIS_SDSAVE 0x0010
-+
-+/* OCP_PHY_STATUS */
-+#define PHY_STAT_MASK 0x0007
-+#define PHY_STAT_LAN_ON 3
-+#define PHY_STAT_PWRDN 5
-+
-+/* OCP_POWER_CFG */
-+#define EEE_CLKDIV_EN 0x8000
-+#define EN_ALDPS 0x0004
-+#define EN_10M_PLLOFF 0x0001
-+
-+/* OCP_EEE_CONFIG1 */
-+#define RG_TXLPI_MSK_HFDUP 0x8000
-+#define RG_MATCLR_EN 0x4000
-+#define EEE_10_CAP 0x2000
-+#define EEE_NWAY_EN 0x1000
-+#define TX_QUIET_EN 0x0200
-+#define RX_QUIET_EN 0x0100
-+#define SDRISETIME 0x0010 /* bit 4 ~ 6 */
-+#define RG_RXLPI_MSK_HFDUP 0x0008
-+#define SDFALLTIME 0x0007 /* bit 0 ~ 2 */
-+
-+/* OCP_EEE_CONFIG2 */
-+#define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */
-+#define RG_DACQUIET_EN 0x0400
-+#define RG_LDVQUIET_EN 0x0200
-+#define RG_CKRSEL 0x0020
-+#define RG_EEEPRG_EN 0x0010
-+
-+/* OCP_EEE_CONFIG3 */
-+#define FST_SNR_EYE_R 0x1500 /* bit 7 ~ 15 */
-+#define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */
-+#define MSK_PH 0x0006 /* bit 0 ~ 3 */
-+
-+/* OCP_EEE_AR */
-+/* bit[15:14] function */
-+#define FUN_ADDR 0x0000
-+#define FUN_DATA 0x4000
-+/* bit[4:0] device addr */
-+#define DEVICE_ADDR 0x0007
-+
-+/* OCP_EEE_DATA */
-+#define EEE_ADDR 0x003C
-+#define EEE_DATA 0x0002
-+
-+/* OCP_EEE_CFG */
-+#define CTAP_SHORT_EN 0x0040
-+#define EEE10_EN 0x0010
-+
-+/* OCP_DOWN_SPEED */
-+#define EN_10M_BGOFF 0x0080
-+
-+/* OCP_EEE_CFG2 */
-+#define MY1000_EEE 0x0004
-+#define MY100_EEE 0x0002
-+
-+/* OCP_ADC_CFG */
-+#define CKADSEL_L 0x0100
-+#define ADC_EN 0x0080
-+#define EN_EMI_L 0x0040
-+
-+/* SRAM_LPF_CFG */
-+#define LPF_AUTO_TUNE 0x8000
-+
-+/* SRAM_10M_AMP1 */
-+#define GDAC_IB_UPALL 0x0008
-+
-+/* SRAM_10M_AMP2 */
-+#define AMP_DN 0x0200
-+
-+/* SRAM_IMPEDANCE */
-+#define RX_DRIVING_MASK 0x6000
-+
-+enum rtl_register_content {
-+ _1000bps = 0x10,
-+ _100bps = 0x08,
-+ _10bps = 0x04,
-+ LINK_STATUS = 0x02,
-+ FULL_DUP = 0x01,
-+};
-+
-+#define RTL8152_MAX_TX 10
-+#define RTL8152_MAX_RX 10
-+#define INTBUFSIZE 2
-+#define CRC_SIZE 4
-+#define TX_ALIGN 4
-+#define RX_ALIGN 8
-+
-+#define INTR_LINK 0x0004
-+
-+#define RTL8152_REQT_READ 0xc0
-+#define RTL8152_REQT_WRITE 0x40
-+#define RTL8152_REQ_GET_REGS 0x05
-+#define RTL8152_REQ_SET_REGS 0x05
-+
-+#define BYTE_EN_DWORD 0xff
-+#define BYTE_EN_WORD 0x33
-+#define BYTE_EN_BYTE 0x11
-+#define BYTE_EN_SIX_BYTES 0x3f
-+#define BYTE_EN_START_MASK 0x0f
-+#define BYTE_EN_END_MASK 0xf0
-+
-+#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN)
-+#define RTL8152_TX_TIMEOUT (HZ)
-+
-+/* rtl8152 flags */
-+enum rtl8152_flags {
-+ RTL8152_UNPLUG = 0,
-+ RTL8152_SET_RX_MODE,
-+ WORK_ENABLE,
-+ RTL8152_LINK_CHG,
-+};
-+
-+/* Define these values to match your device */
-+#define VENDOR_ID_REALTEK 0x0bda
-+#define PRODUCT_ID_RTL8152 0x8152
-+#define PRODUCT_ID_RTL8153 0x8153
-+
-+#define VENDOR_ID_SAMSUNG 0x04e8
-+#define PRODUCT_ID_SAMSUNG 0xa101
-+
-+#define VENDOR_ID_LENOVO 0x17ef
-+#define PRODUCT_ID_LENOVO 0x7205
-+
-+#define VENDOR_ID_NVIDIA 0x0955
-+#define PRODUCT_ID_NVIDIA 0x09ff
-+
-+
-+#define MCU_TYPE_PLA 0x0100
-+#define MCU_TYPE_USB 0x0000
-+
-+struct rx_desc {
-+ __le32 opts1;
-+#define RX_LEN_MASK 0x7fff
-+ __le32 opts2;
-+ __le32 opts3;
-+ __le32 opts4;
-+ __le32 opts5;
-+ __le32 opts6;
-+};
-+
-+struct tx_desc {
-+ __le32 opts1;
-+#define TX_FS (1 << 31) /* First segment of a packet */
-+#define TX_LS (1 << 30) /* Final segment of a packet */
-+#define TX_LEN_MASK 0x3ffff
-+
-+ __le32 opts2;
-+#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */
-+#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */
-+#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */
-+#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */
-+};
-+
-+struct r8152;
-+
-+struct rx_agg {
-+ struct list_head list;
-+ struct urb *urb;
-+ struct r8152 *context;
-+ void *buffer;
-+ void *head;
-+};
-+
-+struct tx_agg {
-+ struct list_head list;
-+ struct urb *urb;
-+ struct r8152 *context;
-+ void *buffer;
-+ void *head;
-+ u32 skb_num;
-+ u32 skb_len;
-+};
-+
-+struct r8152 {
-+ unsigned long flags;
-+ struct usb_device *udev;
-+ struct tasklet_struct tl;
-+ struct usb_interface *intf;
-+ struct net_device *netdev;
-+ struct urb *intr_urb;
-+ struct tx_agg tx_info[RTL8152_MAX_TX];
-+ struct rx_agg rx_info[RTL8152_MAX_RX];
-+ struct list_head rx_done, tx_free;
-+ struct sk_buff_head tx_queue;
-+ spinlock_t rx_lock, tx_lock;
-+ struct delayed_work schedule;
-+ struct mii_if_info mii;
-+
-+ struct rtl_ops {
-+ void (*init)(struct r8152 *);
-+ int (*enable)(struct r8152 *);
-+ void (*disable)(struct r8152 *);
-+ void (*down)(struct r8152 *);
-+ void (*unload)(struct r8152 *);
-+ } __no_const rtl_ops;
-+
-+ int intr_interval;
-+ u32 msg_enable;
-+ u32 tx_qlen;
-+ u16 ocp_base;
-+ u8 *intr_buff;
-+ u8 version;
-+ u8 speed;
-+};
-+
-+enum rtl_version {
-+ RTL_VER_UNKNOWN = 0,
-+ RTL_VER_01,
-+ RTL_VER_02,
-+ RTL_VER_03,
-+ RTL_VER_04,
-+ RTL_VER_05,
-+ RTL_VER_MAX
-+};
-+
-+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-+ * The RTL chips use a 64 element hash table based on the Ethernet CRC.
-+ */
-+static const int multicast_filter_limit = 32;
-+static unsigned int rx_buf_sz = 16384;
-+
-+static
-+int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
-+{
-+ int ret;
-+ void *tmp;
-+
-+ tmp = kmalloc(size, GFP_KERNEL);
-+ if (!tmp)
-+ return -ENOMEM;
-+
-+ ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
-+ RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-+ value, index, tmp, size, 500);
-+
-+ memcpy(data, tmp, size);
-+ kfree(tmp);
-+
-+ return ret;
-+}
-+
-+static
-+int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
-+{
-+ int ret;
-+ void *tmp;
-+
-+ tmp = kmalloc(size, GFP_KERNEL);
-+ if (!tmp)
-+ return -ENOMEM;
-+
-+ memcpy(tmp, data, size);
-+
-+ ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
-+ RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-+ value, index, tmp, size, 500);
-+
-+ kfree(tmp);
-+ return ret;
-+}
-+
-+static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
-+ void *data, u16 type)
-+{
-+ u16 limit = 64;
-+ int ret = 0;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return -ENODEV;
-+
-+ /* both size and indix must be 4 bytes align */
-+ if ((size & 3) || !size || (index & 3) || !data)
-+ return -EPERM;
-+
-+ if ((u32)index + (u32)size > 0xffff)
-+ return -EPERM;
-+
-+ while (size) {
-+ if (size > limit) {
-+ ret = get_registers(tp, index, type, limit, data);
-+ if (ret < 0)
-+ break;
-+
-+ index += limit;
-+ data += limit;
-+ size -= limit;
-+ } else {
-+ ret = get_registers(tp, index, type, size, data);
-+ if (ret < 0)
-+ break;
-+
-+ index += size;
-+ data += size;
-+ size = 0;
-+ break;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
-+ u16 size, void *data, u16 type)
-+{
-+ int ret;
-+ u16 byteen_start, byteen_end, byen;
-+ u16 limit = 512;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return -ENODEV;
-+
-+ /* both size and indix must be 4 bytes align */
-+ if ((size & 3) || !size || (index & 3) || !data)
-+ return -EPERM;
-+
-+ if ((u32)index + (u32)size > 0xffff)
-+ return -EPERM;
-+
-+ byteen_start = byteen & BYTE_EN_START_MASK;
-+ byteen_end = byteen & BYTE_EN_END_MASK;
-+
-+ byen = byteen_start | (byteen_start << 4);
-+ ret = set_registers(tp, index, type | byen, 4, data);
-+ if (ret < 0)
-+ goto error1;
-+
-+ index += 4;
-+ data += 4;
-+ size -= 4;
-+
-+ if (size) {
-+ size -= 4;
-+
-+ while (size) {
-+ if (size > limit) {
-+ ret = set_registers(tp, index,
-+ type | BYTE_EN_DWORD,
-+ limit, data);
-+ if (ret < 0)
-+ goto error1;
-+
-+ index += limit;
-+ data += limit;
-+ size -= limit;
-+ } else {
-+ ret = set_registers(tp, index,
-+ type | BYTE_EN_DWORD,
-+ size, data);
-+ if (ret < 0)
-+ goto error1;
-+
-+ index += size;
-+ data += size;
-+ size = 0;
-+ break;
-+ }
-+ }
-+
-+ byen = byteen_end | (byteen_end >> 4);
-+ ret = set_registers(tp, index, type | byen, 4, data);
-+ if (ret < 0)
-+ goto error1;
-+ }
-+
-+error1:
-+ return ret;
-+}
-+
-+static inline
-+int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
-+{
-+ return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
-+}
-+
-+static inline
-+int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
-+{
-+ return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
-+}
-+
-+static inline
-+int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
-+{
-+ return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB);
-+}
-+
-+static inline
-+int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
-+{
-+ return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
-+}
-+
-+static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
-+{
-+ __le32 data;
-+
-+ generic_ocp_read(tp, index, sizeof(data), &data, type);
-+
-+ return __le32_to_cpu(data);
-+}
-+
-+static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
-+{
-+ __le32 tmp = __cpu_to_le32(data);
-+
-+ generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
-+}
-+
-+static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
-+{
-+ u32 data;
-+ __le32 tmp;
-+ u8 shift = index & 2;
-+
-+ index &= ~3;
-+
-+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-+
-+ data = __le32_to_cpu(tmp);
-+ data >>= (shift * 8);
-+ data &= 0xffff;
-+
-+ return (u16)data;
-+}
-+
-+static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
-+{
-+ u32 mask = 0xffff;
-+ __le32 tmp;
-+ u16 byen = BYTE_EN_WORD;
-+ u8 shift = index & 2;
-+
-+ data &= mask;
-+
-+ if (index & 2) {
-+ byen <<= shift;
-+ mask <<= (shift * 8);
-+ data <<= (shift * 8);
-+ index &= ~3;
-+ }
-+
-+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-+
-+ data |= __le32_to_cpu(tmp) & ~mask;
-+ tmp = __cpu_to_le32(data);
-+
-+ generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
-+}
-+
-+static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
-+{
-+ u32 data;
-+ __le32 tmp;
-+ u8 shift = index & 3;
-+
-+ index &= ~3;
-+
-+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-+
-+ data = __le32_to_cpu(tmp);
-+ data >>= (shift * 8);
-+ data &= 0xff;
-+
-+ return (u8)data;
-+}
-+
-+static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
-+{
-+ u32 mask = 0xff;
-+ __le32 tmp;
-+ u16 byen = BYTE_EN_BYTE;
-+ u8 shift = index & 3;
-+
-+ data &= mask;
-+
-+ if (index & 3) {
-+ byen <<= shift;
-+ mask <<= (shift * 8);
-+ data <<= (shift * 8);
-+ index &= ~3;
-+ }
-+
-+ generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-+
-+ data |= __le32_to_cpu(tmp) & ~mask;
-+ tmp = __cpu_to_le32(data);
-+
-+ generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
-+}
-+
-+static u16 ocp_reg_read(struct r8152 *tp, u16 addr)
-+{
-+ u16 ocp_base, ocp_index;
-+
-+ ocp_base = addr & 0xf000;
-+ if (ocp_base != tp->ocp_base) {
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
-+ tp->ocp_base = ocp_base;
-+ }
-+
-+ ocp_index = (addr & 0x0fff) | 0xb000;
-+ return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
-+}
-+
-+static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
-+{
-+ u16 ocp_base, ocp_index;
-+
-+ ocp_base = addr & 0xf000;
-+ if (ocp_base != tp->ocp_base) {
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
-+ tp->ocp_base = ocp_base;
-+ }
-+
-+ ocp_index = (addr & 0x0fff) | 0xb000;
-+ ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
-+}
-+
-+static inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
-+{
-+ ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
-+}
-+
-+static inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
-+{
-+ return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
-+}
-+
-+static void sram_write(struct r8152 *tp, u16 addr, u16 data)
-+{
-+ ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
-+ ocp_reg_write(tp, OCP_SRAM_DATA, data);
-+}
-+
-+static u16 sram_read(struct r8152 *tp, u16 addr)
-+{
-+ ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
-+ return ocp_reg_read(tp, OCP_SRAM_DATA);
-+}
-+
-+static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ if (phy_id != R8152_PHY_ID)
-+ return -EINVAL;
-+
-+ return r8152_mdio_read(tp, reg);
-+}
-+
-+static
-+void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ if (phy_id != R8152_PHY_ID)
-+ return;
-+
-+ r8152_mdio_write(tp, reg, val);
-+}
-+
-+static
-+int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
-+
-+static inline void set_ethernet_addr(struct r8152 *tp)
-+{
-+ struct net_device *dev = tp->netdev;
-+ u8 node_id[8] = {0};
-+
-+ if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
-+ netif_notice(tp, probe, dev, "inet addr fail\n");
-+ else {
-+ memcpy(dev->dev_addr, node_id, dev->addr_len);
-+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-+ }
-+}
-+
-+static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ struct sockaddr *addr = p;
-+
-+ if (!is_valid_ether_addr(addr->sa_data))
-+ return -EADDRNOTAVAIL;
-+
-+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-+
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
-+ pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
-+
-+ return 0;
-+}
-+
-+static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
-+{
-+ return &dev->stats;
-+}
-+
-+static void read_bulk_callback(struct urb *urb)
-+{
-+ struct net_device *netdev;
-+ unsigned long flags;
-+ int status = urb->status;
-+ struct rx_agg *agg;
-+ struct r8152 *tp;
-+ int result;
-+
-+ agg = urb->context;
-+ if (!agg)
-+ return;
-+
-+ tp = agg->context;
-+ if (!tp)
-+ return;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return;
-+
-+ if (!test_bit(WORK_ENABLE, &tp->flags))
-+ return;
-+
-+ netdev = tp->netdev;
-+
-+ /* When link down, the driver would cancel all bulks. */
-+ /* This avoid the re-submitting bulk */
-+ if (!netif_carrier_ok(netdev))
-+ return;
-+
-+ switch (status) {
-+ case 0:
-+ if (urb->actual_length < ETH_ZLEN)
-+ break;
-+
-+ spin_lock_irqsave(&tp->rx_lock, flags);
-+ list_add_tail(&agg->list, &tp->rx_done);
-+ spin_unlock_irqrestore(&tp->rx_lock, flags);
-+ tasklet_schedule(&tp->tl);
-+ return;
-+ case -ESHUTDOWN:
-+ set_bit(RTL8152_UNPLUG, &tp->flags);
-+ netif_device_detach(tp->netdev);
-+ return;
-+ case -ENOENT:
-+ return; /* the urb is in unlink state */
-+ case -ETIME:
-+ if (net_ratelimit())
-+ netdev_warn(netdev, "maybe reset is needed?\n");
-+ break;
-+ default:
-+ if (net_ratelimit())
-+ netdev_warn(netdev, "Rx status %d\n", status);
-+ break;
-+ }
-+
-+ result = r8152_submit_rx(tp, agg, GFP_ATOMIC);
-+ if (result == -ENODEV) {
-+ netif_device_detach(tp->netdev);
-+ } else if (result) {
-+ spin_lock_irqsave(&tp->rx_lock, flags);
-+ list_add_tail(&agg->list, &tp->rx_done);
-+ spin_unlock_irqrestore(&tp->rx_lock, flags);
-+ tasklet_schedule(&tp->tl);
-+ }
-+}
-+
-+static void write_bulk_callback(struct urb *urb)
-+{
-+ struct net_device_stats *stats;
-+ unsigned long flags;
-+ struct tx_agg *agg;
-+ struct r8152 *tp;
-+ int status = urb->status;
-+
-+ agg = urb->context;
-+ if (!agg)
-+ return;
-+
-+ tp = agg->context;
-+ if (!tp)
-+ return;
-+
-+ stats = rtl8152_get_stats(tp->netdev);
-+ if (status) {
-+ if (net_ratelimit())
-+ netdev_warn(tp->netdev, "Tx status %d\n", status);
-+ stats->tx_errors += agg->skb_num;
-+ } else {
-+ stats->tx_packets += agg->skb_num;
-+ stats->tx_bytes += agg->skb_len;
-+ }
-+
-+ spin_lock_irqsave(&tp->tx_lock, flags);
-+ list_add_tail(&agg->list, &tp->tx_free);
-+ spin_unlock_irqrestore(&tp->tx_lock, flags);
-+
-+ if (!netif_carrier_ok(tp->netdev))
-+ return;
-+
-+ if (!test_bit(WORK_ENABLE, &tp->flags))
-+ return;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return;
-+
-+ if (!skb_queue_empty(&tp->tx_queue))
-+ tasklet_schedule(&tp->tl);
-+}
-+
-+static void intr_callback(struct urb *urb)
-+{
-+ struct r8152 *tp;
-+ __le16 *d;
-+ int status = urb->status;
-+ int res;
-+
-+ tp = urb->context;
-+ if (!tp)
-+ return;
-+
-+ if (!test_bit(WORK_ENABLE, &tp->flags))
-+ return;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return;
-+
-+ switch (status) {
-+ case 0: /* success */
-+ break;
-+ case -ECONNRESET: /* unlink */
-+ case -ESHUTDOWN:
-+ netif_device_detach(tp->netdev);
-+ case -ENOENT:
-+ return;
-+ case -EOVERFLOW:
-+ netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
-+ goto resubmit;
-+ /* -EPIPE: should clear the halt */
-+ default:
-+ netif_info(tp, intr, tp->netdev, "intr status %d\n", status);
-+ goto resubmit;
-+ }
-+
-+ d = urb->transfer_buffer;
-+ if (INTR_LINK & __le16_to_cpu(d[0])) {
-+ if (!(tp->speed & LINK_STATUS)) {
-+ set_bit(RTL8152_LINK_CHG, &tp->flags);
-+ schedule_delayed_work(&tp->schedule, 0);
-+ }
-+ } else {
-+ if (tp->speed & LINK_STATUS) {
-+ set_bit(RTL8152_LINK_CHG, &tp->flags);
-+ schedule_delayed_work(&tp->schedule, 0);
-+ }
-+ }
-+
-+resubmit:
-+ res = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (res == -ENODEV)
-+ netif_device_detach(tp->netdev);
-+ else if (res)
-+ netif_err(tp, intr, tp->netdev,
-+ "can't resubmit intr, status %d\n", res);
-+}
-+
-+static inline void *rx_agg_align(void *data)
-+{
-+ return (void *)ALIGN((uintptr_t)data, RX_ALIGN);
-+}
-+
-+static inline void *tx_agg_align(void *data)
-+{
-+ return (void *)ALIGN((uintptr_t)data, TX_ALIGN);
-+}
-+
-+static void free_all_mem(struct r8152 *tp)
-+{
-+ int i;
-+
-+ for (i = 0; i < RTL8152_MAX_RX; i++) {
-+ usb_free_urb(tp->rx_info[i].urb);
-+ tp->rx_info[i].urb = NULL;
-+
-+ kfree(tp->rx_info[i].buffer);
-+ tp->rx_info[i].buffer = NULL;
-+ tp->rx_info[i].head = NULL;
-+ }
-+
-+ for (i = 0; i < RTL8152_MAX_TX; i++) {
-+ usb_free_urb(tp->tx_info[i].urb);
-+ tp->tx_info[i].urb = NULL;
-+
-+ kfree(tp->tx_info[i].buffer);
-+ tp->tx_info[i].buffer = NULL;
-+ tp->tx_info[i].head = NULL;
-+ }
-+
-+ usb_free_urb(tp->intr_urb);
-+ tp->intr_urb = NULL;
-+
-+ kfree(tp->intr_buff);
-+ tp->intr_buff = NULL;
-+}
-+
-+static int alloc_all_mem(struct r8152 *tp)
-+{
-+ struct net_device *netdev = tp->netdev;
-+ struct usb_interface *intf = tp->intf;
-+ struct usb_host_interface *alt = intf->cur_altsetting;
-+ struct usb_host_endpoint *ep_intr = alt->endpoint + 2;
-+ struct urb *urb;
-+ int node, i;
-+ u8 *buf;
-+
-+ node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
-+
-+ spin_lock_init(&tp->rx_lock);
-+ spin_lock_init(&tp->tx_lock);
-+ INIT_LIST_HEAD(&tp->rx_done);
-+ INIT_LIST_HEAD(&tp->tx_free);
-+ skb_queue_head_init(&tp->tx_queue);
-+
-+ for (i = 0; i < RTL8152_MAX_RX; i++) {
-+ buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
-+ if (!buf)
-+ goto err1;
-+
-+ if (buf != rx_agg_align(buf)) {
-+ kfree(buf);
-+ buf = kmalloc_node(rx_buf_sz + RX_ALIGN, GFP_KERNEL,
-+ node);
-+ if (!buf)
-+ goto err1;
-+ }
-+
-+ urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!urb) {
-+ kfree(buf);
-+ goto err1;
-+ }
-+
-+ INIT_LIST_HEAD(&tp->rx_info[i].list);
-+ tp->rx_info[i].context = tp;
-+ tp->rx_info[i].urb = urb;
-+ tp->rx_info[i].buffer = buf;
-+ tp->rx_info[i].head = rx_agg_align(buf);
-+ }
-+
-+ for (i = 0; i < RTL8152_MAX_TX; i++) {
-+ buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
-+ if (!buf)
-+ goto err1;
-+
-+ if (buf != tx_agg_align(buf)) {
-+ kfree(buf);
-+ buf = kmalloc_node(rx_buf_sz + TX_ALIGN, GFP_KERNEL,
-+ node);
-+ if (!buf)
-+ goto err1;
-+ }
-+
-+ urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!urb) {
-+ kfree(buf);
-+ goto err1;
-+ }
-+
-+ INIT_LIST_HEAD(&tp->tx_info[i].list);
-+ tp->tx_info[i].context = tp;
-+ tp->tx_info[i].urb = urb;
-+ tp->tx_info[i].buffer = buf;
-+ tp->tx_info[i].head = tx_agg_align(buf);
-+
-+ list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
-+ }
-+
-+ tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!tp->intr_urb)
-+ goto err1;
-+
-+ tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
-+ if (!tp->intr_buff)
-+ goto err1;
-+
-+ tp->intr_interval = (int)ep_intr->desc.bInterval;
-+ usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
-+ tp->intr_buff, INTBUFSIZE, intr_callback,
-+ tp, tp->intr_interval);
-+
-+ return 0;
-+
-+err1:
-+ free_all_mem(tp);
-+ return -ENOMEM;
-+}
-+
-+static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
-+{
-+ struct tx_agg *agg = NULL;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&tp->tx_lock, flags);
-+ if (!list_empty(&tp->tx_free)) {
-+ struct list_head *cursor;
-+
-+ cursor = tp->tx_free.next;
-+ list_del_init(cursor);
-+ agg = list_entry(cursor, struct tx_agg, list);
-+ }
-+ spin_unlock_irqrestore(&tp->tx_lock, flags);
-+
-+ return agg;
-+}
-+
-+static void
-+r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
-+{
-+ memset(desc, 0, sizeof(*desc));
-+
-+ desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
-+
-+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
-+ __be16 protocol;
-+ u8 ip_protocol;
-+ u32 opts2 = 0;
-+
-+ if (skb->protocol == htons(ETH_P_8021Q))
-+ protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-+ else
-+ protocol = skb->protocol;
-+
-+ switch (protocol) {
-+ case htons(ETH_P_IP):
-+ opts2 |= IPV4_CS;
-+ ip_protocol = ip_hdr(skb)->protocol;
-+ break;
-+
-+ case htons(ETH_P_IPV6):
-+ opts2 |= IPV6_CS;
-+ ip_protocol = ipv6_hdr(skb)->nexthdr;
-+ break;
-+
-+ default:
-+ ip_protocol = IPPROTO_RAW;
-+ break;
-+ }
-+
-+ if (ip_protocol == IPPROTO_TCP) {
-+ opts2 |= TCP_CS;
-+ opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17;
-+ } else if (ip_protocol == IPPROTO_UDP) {
-+ opts2 |= UDP_CS;
-+ } else {
-+ WARN_ON_ONCE(1);
-+ }
-+
-+ desc->opts2 = cpu_to_le32(opts2);
-+ }
-+}
-+
-+static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
-+{
-+ int remain;
-+ u8 *tx_data;
-+
-+ tx_data = agg->head;
-+ agg->skb_num = agg->skb_len = 0;
-+ remain = rx_buf_sz;
-+
-+ while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
-+ struct tx_desc *tx_desc;
-+ struct sk_buff *skb;
-+ unsigned int len;
-+
-+ skb = skb_dequeue(&tp->tx_queue);
-+ if (!skb)
-+ break;
-+
-+ remain -= sizeof(*tx_desc);
-+ len = skb->len;
-+ if (remain < len) {
-+ skb_queue_head(&tp->tx_queue, skb);
-+ break;
-+ }
-+
-+ tx_data = tx_agg_align(tx_data);
-+ tx_desc = (struct tx_desc *)tx_data;
-+ tx_data += sizeof(*tx_desc);
-+
-+ r8152_tx_csum(tp, tx_desc, skb);
-+ memcpy(tx_data, skb->data, len);
-+ agg->skb_num++;
-+ agg->skb_len += len;
-+ dev_kfree_skb_any(skb);
-+
-+ tx_data += len;
-+ remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
-+ }
-+
-+ netif_tx_lock(tp->netdev);
-+
-+ if (netif_queue_stopped(tp->netdev) &&
-+ skb_queue_len(&tp->tx_queue) < tp->tx_qlen)
-+ netif_wake_queue(tp->netdev);
-+
-+ netif_tx_unlock(tp->netdev);
-+
-+ usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
-+ agg->head, (int)(tx_data - (u8 *)agg->head),
-+ (usb_complete_t)write_bulk_callback, agg);
-+
-+ return usb_submit_urb(agg->urb, GFP_ATOMIC);
-+}
-+
-+static void rx_bottom(struct r8152 *tp)
-+{
-+ unsigned long flags;
-+ struct list_head *cursor, *next;
-+
-+ spin_lock_irqsave(&tp->rx_lock, flags);
-+ list_for_each_safe(cursor, next, &tp->rx_done) {
-+ struct rx_desc *rx_desc;
-+ struct rx_agg *agg;
-+ int len_used = 0;
-+ struct urb *urb;
-+ u8 *rx_data;
-+ int ret;
-+
-+ list_del_init(cursor);
-+ spin_unlock_irqrestore(&tp->rx_lock, flags);
-+
-+ agg = list_entry(cursor, struct rx_agg, list);
-+ urb = agg->urb;
-+ if (urb->actual_length < ETH_ZLEN)
-+ goto submit;
-+
-+ rx_desc = agg->head;
-+ rx_data = agg->head;
-+ len_used += sizeof(struct rx_desc);
-+
-+ while (urb->actual_length > len_used) {
-+ struct net_device *netdev = tp->netdev;
-+ struct net_device_stats *stats;
-+ unsigned int pkt_len;
-+ struct sk_buff *skb;
-+
-+ pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
-+ if (pkt_len < ETH_ZLEN)
-+ break;
-+
-+ len_used += pkt_len;
-+ if (urb->actual_length < len_used)
-+ break;
-+
-+ stats = rtl8152_get_stats(netdev);
-+
-+ pkt_len -= CRC_SIZE;
-+ rx_data += sizeof(struct rx_desc);
-+
-+ skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
-+ if (!skb) {
-+ stats->rx_dropped++;
-+ break;
-+ }
-+ memcpy(skb->data, rx_data, pkt_len);
-+ skb_put(skb, pkt_len);
-+ skb->protocol = eth_type_trans(skb, netdev);
-+ netif_rx(skb);
-+ stats->rx_packets++;
-+ stats->rx_bytes += pkt_len;
-+
-+ rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
-+ rx_desc = (struct rx_desc *)rx_data;
-+ len_used = (int)(rx_data - (u8 *)agg->head);
-+ len_used += sizeof(struct rx_desc);
-+ }
-+
-+submit:
-+ ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
-+ spin_lock_irqsave(&tp->rx_lock, flags);
-+ if (ret && ret != -ENODEV) {
-+ list_add_tail(&agg->list, next);
-+ tasklet_schedule(&tp->tl);
-+ }
-+ }
-+ spin_unlock_irqrestore(&tp->rx_lock, flags);
-+}
-+
-+static void tx_bottom(struct r8152 *tp)
-+{
-+ int res;
-+
-+ do {
-+ struct tx_agg *agg;
-+
-+ if (skb_queue_empty(&tp->tx_queue))
-+ break;
-+
-+ agg = r8152_get_tx_agg(tp);
-+ if (!agg)
-+ break;
-+
-+ res = r8152_tx_agg_fill(tp, agg);
-+ if (res) {
-+ struct net_device_stats *stats;
-+ struct net_device *netdev;
-+ unsigned long flags;
-+
-+ netdev = tp->netdev;
-+ stats = rtl8152_get_stats(netdev);
-+
-+ if (res == -ENODEV) {
-+ netif_device_detach(netdev);
-+ } else {
-+ netif_warn(tp, tx_err, netdev,
-+ "failed tx_urb %d\n", res);
-+ stats->tx_dropped += agg->skb_num;
-+ spin_lock_irqsave(&tp->tx_lock, flags);
-+ list_add_tail(&agg->list, &tp->tx_free);
-+ spin_unlock_irqrestore(&tp->tx_lock, flags);
-+ }
-+ }
-+ } while (res == 0);
-+}
-+
-+static void bottom_half(unsigned long data)
-+{
-+ struct r8152 *tp;
-+
-+ tp = (struct r8152 *)data;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ return;
-+
-+ if (!test_bit(WORK_ENABLE, &tp->flags))
-+ return;
-+
-+ /* When link down, the driver would cancel all bulks. */
-+ /* This avoid the re-submitting bulk */
-+ if (!netif_carrier_ok(tp->netdev))
-+ return;
-+
-+ rx_bottom(tp);
-+ tx_bottom(tp);
-+}
-+
-+static
-+int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
-+{
-+ usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
-+ agg->head, rx_buf_sz,
-+ (usb_complete_t)read_bulk_callback, agg);
-+
-+ return usb_submit_urb(agg->urb, mem_flags);
-+}
-+
-+static void rtl8152_tx_timeout(struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ int i;
-+
-+ netif_warn(tp, tx_err, netdev, "Tx timeout\n");
-+ for (i = 0; i < RTL8152_MAX_TX; i++)
-+ usb_unlink_urb(tp->tx_info[i].urb);
-+}
-+
-+static void rtl8152_set_rx_mode(struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ if (tp->speed & LINK_STATUS) {
-+ set_bit(RTL8152_SET_RX_MODE, &tp->flags);
-+ schedule_delayed_work(&tp->schedule, 0);
-+ }
-+}
-+
-+static void _rtl8152_set_rx_mode(struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ u32 mc_filter[2]; /* Multicast hash filter */
-+ __le32 tmp[2];
-+ u32 ocp_data;
-+
-+ clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
-+ netif_stop_queue(netdev);
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data &= ~RCR_ACPT_ALL;
-+ ocp_data |= RCR_AB | RCR_APM;
-+
-+ if (netdev->flags & IFF_PROMISC) {
-+ /* Unconditionally log net taps. */
-+ netif_notice(tp, link, netdev, "Promiscuous mode enabled\n");
-+ ocp_data |= RCR_AM | RCR_AAP;
-+ mc_filter[1] = mc_filter[0] = 0xffffffff;
-+ } else if ((netdev_mc_count(netdev) > multicast_filter_limit) ||
-+ (netdev->flags & IFF_ALLMULTI)) {
-+ /* Too many to filter perfectly -- accept all multicasts. */
-+ ocp_data |= RCR_AM;
-+ mc_filter[1] = mc_filter[0] = 0xffffffff;
-+ } else {
-+ struct netdev_hw_addr *ha;
-+
-+ mc_filter[1] = mc_filter[0] = 0;
-+ netdev_for_each_mc_addr(ha, netdev) {
-+ int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-+ ocp_data |= RCR_AM;
-+ }
-+ }
-+
-+ tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
-+ tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
-+
-+ pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+ netif_wake_queue(netdev);
-+}
-+
-+static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
-+ struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ skb_tx_timestamp(skb);
-+
-+ skb_queue_tail(&tp->tx_queue, skb);
-+
-+ if (list_empty(&tp->tx_free) &&
-+ skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
-+ netif_stop_queue(netdev);
-+
-+ if (!list_empty(&tp->tx_free))
-+ tasklet_schedule(&tp->tl);
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+static void r8152b_reset_packet_filter(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
-+ ocp_data &= ~FMC_FCR_MCU_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
-+ ocp_data |= FMC_FCR_MCU_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
-+}
-+
-+static void rtl8152_nic_reset(struct r8152 *tp)
-+{
-+ int i;
-+
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
-+
-+ for (i = 0; i < 1000; i++) {
-+ if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
-+ break;
-+ udelay(100);
-+ }
-+}
-+
-+static void set_tx_qlen(struct r8152 *tp)
-+{
-+ struct net_device *netdev = tp->netdev;
-+
-+ tp->tx_qlen = rx_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
-+ sizeof(struct tx_desc));
-+}
-+
-+static inline u8 rtl8152_get_speed(struct r8152 *tp)
-+{
-+ return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
-+}
-+
-+static void rtl_set_eee_plus(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ u8 speed;
-+
-+ speed = rtl8152_get_speed(tp);
-+ if (speed & _10bps) {
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
-+ ocp_data |= EEEP_CR_EEEP_TX;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
-+ } else {
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
-+ ocp_data &= ~EEEP_CR_EEEP_TX;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
-+ }
-+}
-+
-+static int rtl_enable(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i, ret;
-+
-+ r8152b_reset_packet_filter(tp);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
-+ ocp_data |= CR_RE | CR_TE;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data &= ~RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ INIT_LIST_HEAD(&tp->rx_done);
-+ ret = 0;
-+ for (i = 0; i < RTL8152_MAX_RX; i++) {
-+ INIT_LIST_HEAD(&tp->rx_info[i].list);
-+ ret |= r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
-+ }
-+
-+ return ret;
-+}
-+
-+static int rtl8152_enable(struct r8152 *tp)
-+{
-+ set_tx_qlen(tp);
-+ rtl_set_eee_plus(tp);
-+
-+ return rtl_enable(tp);
-+}
-+
-+static void r8153_set_rx_agg(struct r8152 *tp)
-+{
-+ u8 speed;
-+
-+ speed = rtl8152_get_speed(tp);
-+ if (speed & _1000bps) {
-+ if (tp->udev->speed == USB_SPEED_SUPER) {
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH,
-+ RX_THR_SUPPER);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
-+ EARLY_AGG_SUPPER);
-+ } else {
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH,
-+ RX_THR_HIGH);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
-+ EARLY_AGG_HIGH);
-+ }
-+ } else {
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_SLOW);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG,
-+ EARLY_AGG_SLOW);
-+ }
-+}
-+
-+static int rtl8153_enable(struct r8152 *tp)
-+{
-+ set_tx_qlen(tp);
-+ rtl_set_eee_plus(tp);
-+ r8153_set_rx_agg(tp);
-+
-+ return rtl_enable(tp);
-+}
-+
-+static void rtl8152_disable(struct r8152 *tp)
-+{
-+ struct net_device_stats *stats = rtl8152_get_stats(tp->netdev);
-+ struct sk_buff *skb;
-+ u32 ocp_data;
-+ int i;
-+
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data &= ~RCR_ACPT_ALL;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+
-+ while ((skb = skb_dequeue(&tp->tx_queue))) {
-+ dev_kfree_skb(skb);
-+ stats->tx_dropped++;
-+ }
-+
-+ for (i = 0; i < RTL8152_MAX_TX; i++)
-+ usb_kill_urb(tp->tx_info[i].urb);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data |= RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ for (i = 0; i < 1000; i++) {
-+ if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ for (i = 0; i < RTL8152_MAX_RX; i++)
-+ usb_kill_urb(tp->rx_info[i].urb);
-+
-+ rtl8152_nic_reset(tp);
-+}
-+
-+static void r8152b_exit_oob(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data &= ~RCR_ACPT_ALL;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data |= RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data &= ~NOW_IS_OOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data &= ~MCU_BORW_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data |= RE_INIT_LL;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ rtl8152_nic_reset(tp);
-+
-+ /* rx share fifo credit full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_DEV_STAT);
-+ ocp_data &= STAT_SPEED_MASK;
-+ if (ocp_data == STAT_SPEED_FULL) {
-+ /* rx share fifo credit near full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
-+ RXFIFO_THR2_FULL);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
-+ RXFIFO_THR3_FULL);
-+ } else {
-+ /* rx share fifo credit near full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
-+ RXFIFO_THR2_HIGH);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
-+ RXFIFO_THR3_HIGH);
-+ }
-+
-+ /* TX share fifo free credit full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
-+
-+ ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
-+ TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-+ ocp_data &= ~CPCR_RX_VLAN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
-+ ocp_data |= TCR0_AUTO_FIFO;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
-+}
-+
-+static void r8152b_enter_oob(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data &= ~NOW_IS_OOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
-+
-+ rtl8152_disable(tp);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data |= RE_INIT_LL;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
-+ ocp_data |= MAGIC_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-+ ocp_data |= CPCR_RX_VLAN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
-+ ocp_data |= ALDPS_PROXY_MODE;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data &= ~RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data |= RCR_APM | RCR_AM | RCR_AB;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+}
-+
-+static void r8152b_disable_aldps(struct r8152 *tp)
-+{
-+ ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
-+ msleep(20);
-+}
-+
-+static inline void r8152b_enable_aldps(struct r8152 *tp)
-+{
-+ ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
-+ LINKENA | DIS_SDSAVE);
-+}
-+
-+static void r8153_hw_phy_cfg(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ u16 data;
-+
-+ ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
-+ r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
-+
-+ if (tp->version == RTL_VER_03) {
-+ data = ocp_reg_read(tp, OCP_EEE_CFG);
-+ data &= ~CTAP_SHORT_EN;
-+ ocp_reg_write(tp, OCP_EEE_CFG, data);
-+ }
-+
-+ data = ocp_reg_read(tp, OCP_POWER_CFG);
-+ data |= EEE_CLKDIV_EN;
-+ ocp_reg_write(tp, OCP_POWER_CFG, data);
-+
-+ data = ocp_reg_read(tp, OCP_DOWN_SPEED);
-+ data |= EN_10M_BGOFF;
-+ ocp_reg_write(tp, OCP_DOWN_SPEED, data);
-+ data = ocp_reg_read(tp, OCP_POWER_CFG);
-+ data |= EN_10M_PLLOFF;
-+ ocp_reg_write(tp, OCP_POWER_CFG, data);
-+ data = sram_read(tp, SRAM_IMPEDANCE);
-+ data &= ~RX_DRIVING_MASK;
-+ sram_write(tp, SRAM_IMPEDANCE, data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
-+ ocp_data |= PFM_PWM_SWITCH;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
-+
-+ data = sram_read(tp, SRAM_LPF_CFG);
-+ data |= LPF_AUTO_TUNE;
-+ sram_write(tp, SRAM_LPF_CFG, data);
-+
-+ data = sram_read(tp, SRAM_10M_AMP1);
-+ data |= GDAC_IB_UPALL;
-+ sram_write(tp, SRAM_10M_AMP1, data);
-+ data = sram_read(tp, SRAM_10M_AMP2);
-+ data |= AMP_DN;
-+ sram_write(tp, SRAM_10M_AMP2, data);
-+}
-+
-+static void r8153_u1u2en(struct r8152 *tp, int enable)
-+{
-+ u8 u1u2[8];
-+
-+ if (enable)
-+ memset(u1u2, 0xff, sizeof(u1u2));
-+ else
-+ memset(u1u2, 0x00, sizeof(u1u2));
-+
-+ usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
-+}
-+
-+static void r8153_u2p3en(struct r8152 *tp, int enable)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
-+ if (enable)
-+ ocp_data |= U2P3_ENABLE;
-+ else
-+ ocp_data &= ~U2P3_ENABLE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
-+}
-+
-+static void r8153_power_cut_en(struct r8152 *tp, int enable)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
-+ if (enable)
-+ ocp_data |= PWR_EN | PHASE2_EN;
-+ else
-+ ocp_data &= ~(PWR_EN | PHASE2_EN);
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
-+ ocp_data &= ~PCUT_STATUS;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
-+}
-+
-+static void r8153_teredo_off(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
-+ ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
-+}
-+
-+static void r8153_first_init(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data |= RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ r8153_teredo_off(tp);
-+
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data &= ~RCR_ACPT_ALL;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+
-+ r8153_hw_phy_cfg(tp);
-+
-+ rtl8152_nic_reset(tp);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data &= ~NOW_IS_OOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data &= ~MCU_BORW_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data |= RE_INIT_LL;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-+ ocp_data &= ~CPCR_RX_VLAN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
-+ ocp_data |= TCR0_AUTO_FIFO;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
-+
-+ rtl8152_nic_reset(tp);
-+
-+ /* rx share fifo credit full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
-+ /* TX share fifo free credit full threshold */
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
-+
-+ /* rx aggregation */
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
-+ ocp_data &= ~RX_AGG_DISABLE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
-+}
-+
-+static void r8153_enter_oob(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data &= ~NOW_IS_OOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ rtl8152_disable(tp);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-+ ocp_data |= RE_INIT_LL;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
-+
-+ for (i = 0; i < 1000; i++) {
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ if (ocp_data & LINK_LIST_READY)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
-+ ocp_data |= MAGIC_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
-+ ocp_data &= ~TEREDO_WAKE_MASK;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-+ ocp_data |= CPCR_RX_VLAN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
-+ ocp_data |= ALDPS_PROXY_MODE;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-+ ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
-+
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-+ ocp_data &= ~RXDY_GATED_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-+
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-+ ocp_data |= RCR_APM | RCR_AM | RCR_AB;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
-+}
-+
-+static void r8153_disable_aldps(struct r8152 *tp)
-+{
-+ u16 data;
-+
-+ data = ocp_reg_read(tp, OCP_POWER_CFG);
-+ data &= ~EN_ALDPS;
-+ ocp_reg_write(tp, OCP_POWER_CFG, data);
-+ msleep(20);
-+}
-+
-+static void r8153_enable_aldps(struct r8152 *tp)
-+{
-+ u16 data;
-+
-+ data = ocp_reg_read(tp, OCP_POWER_CFG);
-+ data |= EN_ALDPS;
-+ ocp_reg_write(tp, OCP_POWER_CFG, data);
-+}
-+
-+static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
-+{
-+ u16 bmcr, anar, gbcr;
-+ int ret = 0;
-+
-+ cancel_delayed_work_sync(&tp->schedule);
-+ anar = r8152_mdio_read(tp, MII_ADVERTISE);
-+ anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
-+ ADVERTISE_100HALF | ADVERTISE_100FULL);
-+ if (tp->mii.supports_gmii) {
-+ gbcr = r8152_mdio_read(tp, MII_CTRL1000);
-+ gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
-+ } else {
-+ gbcr = 0;
-+ }
-+
-+ if (autoneg == AUTONEG_DISABLE) {
-+ if (speed == SPEED_10) {
-+ bmcr = 0;
-+ anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
-+ } else if (speed == SPEED_100) {
-+ bmcr = BMCR_SPEED100;
-+ anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
-+ } else if (speed == SPEED_1000 && tp->mii.supports_gmii) {
-+ bmcr = BMCR_SPEED1000;
-+ gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
-+ } else {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (duplex == DUPLEX_FULL)
-+ bmcr |= BMCR_FULLDPLX;
-+ } else {
-+ if (speed == SPEED_10) {
-+ if (duplex == DUPLEX_FULL)
-+ anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
-+ else
-+ anar |= ADVERTISE_10HALF;
-+ } else if (speed == SPEED_100) {
-+ if (duplex == DUPLEX_FULL) {
-+ anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
-+ anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
-+ } else {
-+ anar |= ADVERTISE_10HALF;
-+ anar |= ADVERTISE_100HALF;
-+ }
-+ } else if (speed == SPEED_1000 && tp->mii.supports_gmii) {
-+ if (duplex == DUPLEX_FULL) {
-+ anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
-+ anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
-+ gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
-+ } else {
-+ anar |= ADVERTISE_10HALF;
-+ anar |= ADVERTISE_100HALF;
-+ gbcr |= ADVERTISE_1000HALF;
-+ }
-+ } else {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
-+ }
-+
-+ if (tp->mii.supports_gmii)
-+ r8152_mdio_write(tp, MII_CTRL1000, gbcr);
-+
-+ r8152_mdio_write(tp, MII_ADVERTISE, anar);
-+ r8152_mdio_write(tp, MII_BMCR, bmcr);
-+
-+out:
-+
-+ return ret;
-+}
-+
-+static void rtl8152_down(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-+ ocp_data &= ~POWER_CUT;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-+
-+ r8152b_disable_aldps(tp);
-+ r8152b_enter_oob(tp);
-+ r8152b_enable_aldps(tp);
-+}
-+
-+static void rtl8153_down(struct r8152 *tp)
-+{
-+ r8153_u1u2en(tp, 0);
-+ r8153_power_cut_en(tp, 0);
-+ r8153_disable_aldps(tp);
-+ r8153_enter_oob(tp);
-+ r8153_enable_aldps(tp);
-+}
-+
-+static void set_carrier(struct r8152 *tp)
-+{
-+ struct net_device *netdev = tp->netdev;
-+ u8 speed;
-+
-+ clear_bit(RTL8152_LINK_CHG, &tp->flags);
-+ speed = rtl8152_get_speed(tp);
-+
-+ if (speed & LINK_STATUS) {
-+ if (!(tp->speed & LINK_STATUS)) {
-+ tp->rtl_ops.enable(tp);
-+ set_bit(RTL8152_SET_RX_MODE, &tp->flags);
-+ netif_carrier_on(netdev);
-+ }
-+ } else {
-+ if (tp->speed & LINK_STATUS) {
-+ netif_carrier_off(netdev);
-+ tasklet_disable(&tp->tl);
-+ tp->rtl_ops.disable(tp);
-+ tasklet_enable(&tp->tl);
-+ }
-+ }
-+ tp->speed = speed;
-+}
-+
-+static void rtl_work_func_t(struct work_struct *work)
-+{
-+ struct r8152 *tp = container_of(work, struct r8152, schedule.work);
-+
-+ if (!test_bit(WORK_ENABLE, &tp->flags))
-+ goto out1;
-+
-+ if (test_bit(RTL8152_UNPLUG, &tp->flags))
-+ goto out1;
-+
-+ if (test_bit(RTL8152_LINK_CHG, &tp->flags))
-+ set_carrier(tp);
-+
-+ if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
-+ _rtl8152_set_rx_mode(tp->netdev);
-+
-+out1:
-+ return;
-+}
-+
-+static int rtl8152_open(struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ int res = 0;
-+
-+ rtl8152_set_speed(tp, AUTONEG_ENABLE,
-+ tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
-+ DUPLEX_FULL);
-+ tp->speed = 0;
-+ netif_carrier_off(netdev);
-+ netif_start_queue(netdev);
-+ set_bit(WORK_ENABLE, &tp->flags);
-+ res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
-+ if (res) {
-+ if (res == -ENODEV)
-+ netif_device_detach(tp->netdev);
-+ netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
-+ res);
-+ }
-+
-+
-+ return res;
-+}
-+
-+static int rtl8152_close(struct net_device *netdev)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ int res = 0;
-+
-+ clear_bit(WORK_ENABLE, &tp->flags);
-+ usb_kill_urb(tp->intr_urb);
-+ cancel_delayed_work_sync(&tp->schedule);
-+ netif_stop_queue(netdev);
-+ tasklet_disable(&tp->tl);
-+ tp->rtl_ops.disable(tp);
-+ tasklet_enable(&tp->tl);
-+
-+ return res;
-+}
-+
-+static void rtl_clear_bp(struct r8152 *tp)
-+{
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
-+ ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
-+ mdelay(3);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
-+}
-+
-+static void r8153_clear_bp(struct r8152 *tp)
-+{
-+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
-+ ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
-+ rtl_clear_bp(tp);
-+}
-+
-+static void r8152b_enable_eee(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR);
-+ ocp_data |= EEE_RX_EN | EEE_TX_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
-+ ocp_reg_write(tp, OCP_EEE_CONFIG1, RG_TXLPI_MSK_HFDUP | RG_MATCLR_EN |
-+ EEE_10_CAP | EEE_NWAY_EN |
-+ TX_QUIET_EN | RX_QUIET_EN |
-+ SDRISETIME | RG_RXLPI_MSK_HFDUP |
-+ SDFALLTIME);
-+ ocp_reg_write(tp, OCP_EEE_CONFIG2, RG_LPIHYS_NUM | RG_DACQUIET_EN |
-+ RG_LDVQUIET_EN | RG_CKRSEL |
-+ RG_EEEPRG_EN);
-+ ocp_reg_write(tp, OCP_EEE_CONFIG3, FST_SNR_EYE_R | RG_LFS_SEL | MSK_PH);
-+ ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | DEVICE_ADDR);
-+ ocp_reg_write(tp, OCP_EEE_DATA, EEE_ADDR);
-+ ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | DEVICE_ADDR);
-+ ocp_reg_write(tp, OCP_EEE_DATA, EEE_DATA);
-+ ocp_reg_write(tp, OCP_EEE_AR, 0x0000);
-+}
-+
-+static void r8153_enable_eee(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ u16 data;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR);
-+ ocp_data |= EEE_RX_EN | EEE_TX_EN;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
-+ data = ocp_reg_read(tp, OCP_EEE_CFG);
-+ data |= EEE10_EN;
-+ ocp_reg_write(tp, OCP_EEE_CFG, data);
-+ data = ocp_reg_read(tp, OCP_EEE_CFG2);
-+ data |= MY1000_EEE | MY100_EEE;
-+ ocp_reg_write(tp, OCP_EEE_CFG2, data);
-+}
-+
-+static void r8152b_enable_fc(struct r8152 *tp)
-+{
-+ u16 anar;
-+
-+ anar = r8152_mdio_read(tp, MII_ADVERTISE);
-+ anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
-+ r8152_mdio_write(tp, MII_ADVERTISE, anar);
-+}
-+
-+static void r8152b_hw_phy_cfg(struct r8152 *tp)
-+{
-+ r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
-+ r8152b_disable_aldps(tp);
-+}
-+
-+static void r8152b_init(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ rtl_clear_bp(tp);
-+
-+ if (tp->version == RTL_VER_01) {
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
-+ ocp_data &= ~LED_MODE_MASK;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
-+ }
-+
-+ r8152b_hw_phy_cfg(tp);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-+ ocp_data &= ~POWER_CUT;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
-+ ocp_data &= ~RESUME_INDICATE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
-+
-+ r8152b_exit_oob(tp);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
-+ ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
-+ ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
-+ ocp_data &= ~MCU_CLK_RATIO_MASK;
-+ ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
-+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
-+ ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
-+ SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
-+
-+ r8152b_enable_eee(tp);
-+ r8152b_enable_aldps(tp);
-+ r8152b_enable_fc(tp);
-+
-+ r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
-+ BMCR_ANRESTART);
-+ for (i = 0; i < 100; i++) {
-+ udelay(100);
-+ if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET))
-+ break;
-+ }
-+
-+ /* enable rx aggregation */
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
-+ ocp_data &= ~RX_AGG_DISABLE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
-+}
-+
-+static void r8153_init(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ int i;
-+
-+ r8153_u1u2en(tp, 0);
-+
-+ for (i = 0; i < 500; i++) {
-+ if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
-+ AUTOLOAD_DONE)
-+ break;
-+ msleep(20);
-+ }
-+
-+ for (i = 0; i < 500; i++) {
-+ ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
-+ if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
-+ break;
-+ msleep(20);
-+ }
-+
-+ r8153_u2p3en(tp, 0);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
-+ ocp_data &= ~TIMER11_EN;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
-+
-+ r8153_clear_bp(tp);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
-+ ocp_data &= ~LED_MODE_MASK;
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
-+
-+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL);
-+ ocp_data &= ~LPM_TIMER_MASK;
-+ if (tp->udev->speed == USB_SPEED_SUPER)
-+ ocp_data |= LPM_TIMER_500US;
-+ else
-+ ocp_data |= LPM_TIMER_500MS;
-+ ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data);
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2);
-+ ocp_data &= ~SEN_VAL_MASK;
-+ ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
-+
-+ r8153_power_cut_en(tp, 0);
-+ r8153_u1u2en(tp, 1);
-+
-+ r8153_first_init(tp);
-+
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3,
-+ PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN |
-+ U1U2_SPDWN_EN | L1_SPDWN_EN);
-+ ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4,
-+ PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN |
-+ TP100_SPDWN_EN | TP500_SPDWN_EN | TP1000_SPDWN_EN |
-+ EEE_SPDWN_EN);
-+
-+ r8153_enable_eee(tp);
-+ r8153_enable_aldps(tp);
-+ r8152b_enable_fc(tp);
-+
-+ r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
-+ BMCR_ANRESTART);
-+}
-+
-+static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct r8152 *tp = usb_get_intfdata(intf);
-+
-+ netif_device_detach(tp->netdev);
-+
-+ if (netif_running(tp->netdev)) {
-+ clear_bit(WORK_ENABLE, &tp->flags);
-+ usb_kill_urb(tp->intr_urb);
-+ cancel_delayed_work_sync(&tp->schedule);
-+ tasklet_disable(&tp->tl);
-+ }
-+
-+ tp->rtl_ops.down(tp);
-+
-+ return 0;
-+}
-+
-+static int rtl8152_resume(struct usb_interface *intf)
-+{
-+ struct r8152 *tp = usb_get_intfdata(intf);
-+
-+ tp->rtl_ops.init(tp);
-+ netif_device_attach(tp->netdev);
-+ if (netif_running(tp->netdev)) {
-+ rtl8152_set_speed(tp, AUTONEG_ENABLE,
-+ tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
-+ DUPLEX_FULL);
-+ tp->speed = 0;
-+ netif_carrier_off(tp->netdev);
-+ set_bit(WORK_ENABLE, &tp->flags);
-+ usb_submit_urb(tp->intr_urb, GFP_KERNEL);
-+ tasklet_enable(&tp->tl);
-+ }
-+
-+ return 0;
-+}
-+
-+static void rtl8152_get_drvinfo(struct net_device *netdev,
-+ struct ethtool_drvinfo *info)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ strncpy(info->driver, MODULENAME, ETHTOOL_BUSINFO_LEN);
-+ strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-+ usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
-+}
-+
-+static
-+int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+
-+ if (!tp->mii.mdio_read)
-+ return -EOPNOTSUPP;
-+
-+ return mii_ethtool_gset(&tp->mii, cmd);
-+}
-+
-+static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-+{
-+ struct r8152 *tp = netdev_priv(dev);
-+
-+ return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
-+}
-+
-+static struct ethtool_ops ops = {
-+ .get_drvinfo = rtl8152_get_drvinfo,
-+ .get_settings = rtl8152_get_settings,
-+ .set_settings = rtl8152_set_settings,
-+ .get_link = ethtool_op_get_link,
-+};
-+
-+static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-+{
-+ struct r8152 *tp = netdev_priv(netdev);
-+ struct mii_ioctl_data *data = if_mii(rq);
-+ int res = 0;
-+
-+ switch (cmd) {
-+ case SIOCGMIIPHY:
-+ data->phy_id = R8152_PHY_ID; /* Internal PHY */
-+ break;
-+
-+ case SIOCGMIIREG:
-+ data->val_out = r8152_mdio_read(tp, data->reg_num);
-+ break;
-+
-+ case SIOCSMIIREG:
-+ if (!capable(CAP_NET_ADMIN)) {
-+ res = -EPERM;
-+ break;
-+ }
-+ r8152_mdio_write(tp, data->reg_num, data->val_in);
-+ break;
-+
-+ default:
-+ res = -EOPNOTSUPP;
-+ }
-+
-+ return res;
-+}
-+
-+static const struct net_device_ops rtl8152_netdev_ops = {
-+ .ndo_open = rtl8152_open,
-+ .ndo_stop = rtl8152_close,
-+ .ndo_do_ioctl = rtl8152_ioctl,
-+ .ndo_start_xmit = rtl8152_start_xmit,
-+ .ndo_tx_timeout = rtl8152_tx_timeout,
-+ .ndo_set_rx_mode = rtl8152_set_rx_mode,
-+ .ndo_set_mac_address = rtl8152_set_mac_address,
-+
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+};
-+
-+static void r8152b_get_version(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+ u16 version;
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
-+ version = (u16)(ocp_data & VERSION_MASK);
-+
-+ switch (version) {
-+ case 0x4c00:
-+ tp->version = RTL_VER_01;
-+ break;
-+ case 0x4c10:
-+ tp->version = RTL_VER_02;
-+ break;
-+ case 0x5c00:
-+ tp->version = RTL_VER_03;
-+ tp->mii.supports_gmii = 1;
-+ break;
-+ case 0x5c10:
-+ tp->version = RTL_VER_04;
-+ tp->mii.supports_gmii = 1;
-+ break;
-+ case 0x5c20:
-+ tp->version = RTL_VER_05;
-+ tp->mii.supports_gmii = 1;
-+ break;
-+ default:
-+ netif_info(tp, probe, tp->netdev,
-+ "Unknown version 0x%04x\n", version);
-+ break;
-+ }
-+}
-+
-+static void rtl8152_unload(struct r8152 *tp)
-+{
-+ u32 ocp_data;
-+
-+ if (tp->version != RTL_VER_01) {
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-+ ocp_data |= POWER_CUT;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-+ }
-+
-+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
-+ ocp_data &= ~RESUME_INDICATE;
-+ ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
-+}
-+
-+static void rtl8153_unload(struct r8152 *tp)
-+{
-+ r8153_power_cut_en(tp, 1);
-+}
-+
-+static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
-+{
-+ struct rtl_ops *ops = &tp->rtl_ops;
-+ int ret = -ENODEV;
-+
-+ switch (id->idVendor) {
-+ case VENDOR_ID_REALTEK:
-+ switch (id->idProduct) {
-+ case PRODUCT_ID_RTL8152:
-+ ops->init = r8152b_init;
-+ ops->enable = rtl8152_enable;
-+ ops->disable = rtl8152_disable;
-+ ops->down = rtl8152_down;
-+ ops->unload = rtl8152_unload;
-+ ret = 0;
-+ break;
-+ case PRODUCT_ID_RTL8153:
-+ ops->init = r8153_init;
-+ ops->enable = rtl8153_enable;
-+ ops->disable = rtl8152_disable;
-+ ops->down = rtl8153_down;
-+ ops->unload = rtl8153_unload;
-+ ret = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+
-+ case VENDOR_ID_SAMSUNG:
-+ switch (id->idProduct) {
-+ case PRODUCT_ID_SAMSUNG:
-+ ops->init = r8153_init;
-+ ops->enable = rtl8153_enable;
-+ ops->disable = rtl8152_disable;
-+ ops->down = rtl8153_down;
-+ ops->unload = rtl8153_unload;
-+ ret = 0;
-+ break;
-+ default:
-+ break;
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ if (ret)
-+ netif_err(tp, probe, tp->netdev, "Unknown Device\n");
-+
-+ return ret;
-+}
-+
-+static int rtl8152_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_device *udev = interface_to_usbdev(intf);
-+ struct r8152 *tp;
-+ struct net_device *netdev;
-+ int ret;
-+
-+ if (udev->actconfig->desc.bConfigurationValue != 1) {
-+ usb_driver_set_configuration(udev, 1);
-+ return -ENODEV;
-+ }
-+
-+ usb_reset_device(udev);
-+ netdev = alloc_etherdev(sizeof(struct r8152));
-+ if (!netdev) {
-+ dev_err(&intf->dev, "Out of memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ SET_NETDEV_DEV(netdev, &intf->dev);
-+ tp = netdev_priv(netdev);
-+ tp->msg_enable = 0x7FFF;
-+
-+ tp->udev = udev;
-+ tp->netdev = netdev;
-+ tp->intf = intf;
-+
-+ ret = rtl_ops_init(tp, id);
-+ if (ret)
-+ goto out;
-+
-+ tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
-+ INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
-+
-+ netdev->netdev_ops = &rtl8152_netdev_ops;
-+ netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
-+
-+ netdev->features |= NETIF_F_IP_CSUM;
-+ netdev->hw_features = NETIF_F_IP_CSUM;
-+ SET_ETHTOOL_OPS(netdev, &ops);
-+
-+ tp->mii.dev = netdev;
-+ tp->mii.mdio_read = read_mii_word;
-+ tp->mii.mdio_write = write_mii_word;
-+ tp->mii.phy_id_mask = 0x3f;
-+ tp->mii.reg_num_mask = 0x1f;
-+ tp->mii.phy_id = R8152_PHY_ID;
-+ tp->mii.supports_gmii = 0;
-+
-+ r8152b_get_version(tp);
-+ tp->rtl_ops.init(tp);
-+ set_ethernet_addr(tp);
-+
-+ ret = alloc_all_mem(tp);
-+ if (ret)
-+ goto out;
-+
-+ usb_set_intfdata(intf, tp);
-+
-+ ret = register_netdev(netdev);
-+ if (ret != 0) {
-+ netif_err(tp, probe, netdev, "couldn't register the device\n");
-+ goto out1;
-+ }
-+
-+ netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
-+
-+ return 0;
-+
-+out1:
-+ usb_set_intfdata(intf, NULL);
-+out:
-+ free_netdev(netdev);
-+ return ret;
-+}
-+
-+static void rtl8152_disconnect(struct usb_interface *intf)
-+{
-+ struct r8152 *tp = usb_get_intfdata(intf);
-+
-+ usb_set_intfdata(intf, NULL);
-+ if (tp) {
-+ set_bit(RTL8152_UNPLUG, &tp->flags);
-+ tasklet_kill(&tp->tl);
-+ unregister_netdev(tp->netdev);
-+ tp->rtl_ops.unload(tp);
-+ free_all_mem(tp);
-+ free_netdev(tp->netdev);
-+ }
-+}
-+
-+/* table of devices that work with this driver */
-+static struct usb_device_id rtl8152_table[] = {
-+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
-+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
-+ {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
-+ {USB_DEVICE(VENDOR_ID_LENOVO, PRODUCT_ID_LENOVO)},
-+ {USB_DEVICE(VENDOR_ID_NVIDIA, PRODUCT_ID_NVIDIA)},
-+ {}
-+};
-+
-+MODULE_DEVICE_TABLE(usb, rtl8152_table);
-+
-+static struct usb_driver rtl8152_driver = {
-+ .name = MODULENAME,
-+ .id_table = rtl8152_table,
-+ .probe = rtl8152_probe,
-+ .disconnect = rtl8152_disconnect,
-+ .suspend = rtl8152_suspend,
-+ .resume = rtl8152_resume,
-+ .reset_resume = rtl8152_resume,
-+};
-+
-+module_usb_driver(rtl8152_driver);
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/rtl8150.c backports-4.2.6-1/drivers/net/usb/rtl8150.c
---- backports-4.2.6-1.org/drivers/net/usb/rtl8150.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/rtl8150.c 2016-06-28 14:35:18.001973885 +0200
-@@ -0,0 +1,949 @@
-+/*
-+ * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#include <linux/signal.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/mii.h>
-+#include <linux/ethtool.h>
-+#include <linux/usb.h>
-+#include <asm/uaccess.h>
-+
-+/* Version Information */
-+#define DRIVER_VERSION "v0.6.2 (2004/08/27)"
-+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
-+#define DRIVER_DESC "rtl8150 based usb-ethernet driver"
-+
-+#define IDR 0x0120
-+#define MAR 0x0126
-+#define CR 0x012e
-+#define TCR 0x012f
-+#define RCR 0x0130
-+#define TSR 0x0132
-+#define RSR 0x0133
-+#define CON0 0x0135
-+#define CON1 0x0136
-+#define MSR 0x0137
-+#define PHYADD 0x0138
-+#define PHYDAT 0x0139
-+#define PHYCNT 0x013b
-+#define GPPC 0x013d
-+#define BMCR 0x0140
-+#define BMSR 0x0142
-+#define ANAR 0x0144
-+#define ANLP 0x0146
-+#define AER 0x0148
-+#define CSCR 0x014C /* This one has the link status */
-+#define CSCR_LINK_STATUS (1 << 3)
-+
-+#define IDR_EEPROM 0x1202
-+
-+#define PHY_READ 0
-+#define PHY_WRITE 0x20
-+#define PHY_GO 0x40
-+
-+#define MII_TIMEOUT 10
-+#define INTBUFSIZE 8
-+
-+#define RTL8150_REQT_READ 0xc0
-+#define RTL8150_REQT_WRITE 0x40
-+#define RTL8150_REQ_GET_REGS 0x05
-+#define RTL8150_REQ_SET_REGS 0x05
-+
-+
-+/* Transmit status register errors */
-+#define TSR_ECOL (1<<5)
-+#define TSR_LCOL (1<<4)
-+#define TSR_LOSS_CRS (1<<3)
-+#define TSR_JBR (1<<2)
-+#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR)
-+/* Receive status register errors */
-+#define RSR_CRC (1<<2)
-+#define RSR_FAE (1<<1)
-+#define RSR_ERRORS (RSR_CRC | RSR_FAE)
-+
-+/* Media status register definitions */
-+#define MSR_DUPLEX (1<<4)
-+#define MSR_SPEED (1<<3)
-+#define MSR_LINK (1<<2)
-+
-+/* Interrupt pipe data */
-+#define INT_TSR 0x00
-+#define INT_RSR 0x01
-+#define INT_MSR 0x02
-+#define INT_WAKSR 0x03
-+#define INT_TXOK_CNT 0x04
-+#define INT_RXLOST_CNT 0x05
-+#define INT_CRERR_CNT 0x06
-+#define INT_COL_CNT 0x07
-+
-+
-+#define RTL8150_MTU 1540
-+#define RTL8150_TX_TIMEOUT (HZ)
-+#define RX_SKB_POOL_SIZE 4
-+
-+/* rtl8150 flags */
-+#define RTL8150_HW_CRC 0
-+#define RX_REG_SET 1
-+#define RTL8150_UNPLUG 2
-+#define RX_URB_FAIL 3
-+
-+/* Define these values to match your device */
-+#define VENDOR_ID_REALTEK 0x0bda
-+#define VENDOR_ID_MELCO 0x0411
-+#define VENDOR_ID_MICRONET 0x3980
-+#define VENDOR_ID_LONGSHINE 0x07b8
-+#define VENDOR_ID_OQO 0x1557
-+#define VENDOR_ID_ZYXEL 0x0586
-+
-+#define PRODUCT_ID_RTL8150 0x8150
-+#define PRODUCT_ID_LUAKTX 0x0012
-+#define PRODUCT_ID_LCS8138TX 0x401a
-+#define PRODUCT_ID_SP128AR 0x0003
-+#define PRODUCT_ID_PRESTIGE 0x401a
-+
-+#undef EEPROM_WRITE
-+
-+/* table of devices that work with this driver */
-+static struct usb_device_id rtl8150_table[] = {
-+ {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
-+ {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
-+ {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
-+ {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
-+ {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
-+ {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
-+ {}
-+};
-+
-+MODULE_DEVICE_TABLE(usb, rtl8150_table);
-+
-+struct rtl8150 {
-+ unsigned long flags;
-+ struct usb_device *udev;
-+ struct tasklet_struct tl;
-+ struct net_device *netdev;
-+ struct urb *rx_urb, *tx_urb, *intr_urb;
-+ struct sk_buff *tx_skb, *rx_skb;
-+ struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
-+ spinlock_t rx_pool_lock;
-+ struct usb_ctrlrequest dr;
-+ int intr_interval;
-+ u8 *intr_buff;
-+ u8 phy;
-+};
-+
-+typedef struct rtl8150 rtl8150_t;
-+
-+struct async_req {
-+ struct usb_ctrlrequest dr;
-+ u16 rx_creg;
-+};
-+
-+static const char driver_name [] = "rtl8150";
-+
-+/*
-+**
-+** device related part of the code
-+**
-+*/
-+static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
-+{
-+ return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
-+ RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-+ indx, 0, data, size, 500);
-+}
-+
-+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
-+{
-+ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
-+ RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-+ indx, 0, data, size, 500);
-+}
-+
-+static void async_set_reg_cb(struct urb *urb)
-+{
-+ struct async_req *req = (struct async_req *)urb->context;
-+ int status = urb->status;
-+
-+ if (status < 0)
-+ dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
-+ kfree(req);
-+ usb_free_urb(urb);
-+}
-+
-+static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg)
-+{
-+ int res = -ENOMEM;
-+ struct urb *async_urb;
-+ struct async_req *req;
-+
-+ req = kmalloc(sizeof(struct async_req), GFP_ATOMIC);
-+ if (req == NULL)
-+ return res;
-+ async_urb = usb_alloc_urb(0, GFP_ATOMIC);
-+ if (async_urb == NULL) {
-+ kfree(req);
-+ return res;
-+ }
-+ req->rx_creg = cpu_to_le16(reg);
-+ req->dr.bRequestType = RTL8150_REQT_WRITE;
-+ req->dr.bRequest = RTL8150_REQ_SET_REGS;
-+ req->dr.wIndex = 0;
-+ req->dr.wValue = cpu_to_le16(indx);
-+ req->dr.wLength = cpu_to_le16(size);
-+ usb_fill_control_urb(async_urb, dev->udev,
-+ usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr,
-+ &req->rx_creg, size, async_set_reg_cb, req);
-+ res = usb_submit_urb(async_urb, GFP_ATOMIC);
-+ if (res) {
-+ if (res == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res);
-+ }
-+ return res;
-+}
-+
-+static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
-+{
-+ int i;
-+ u8 data[3], tmp;
-+
-+ data[0] = phy;
-+ data[1] = data[2] = 0;
-+ tmp = indx | PHY_READ | PHY_GO;
-+ i = 0;
-+
-+ set_registers(dev, PHYADD, sizeof(data), data);
-+ set_registers(dev, PHYCNT, 1, &tmp);
-+ do {
-+ get_registers(dev, PHYCNT, 1, data);
-+ } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
-+
-+ if (i <= MII_TIMEOUT) {
-+ get_registers(dev, PHYDAT, 2, data);
-+ *reg = data[0] | (data[1] << 8);
-+ return 0;
-+ } else
-+ return 1;
-+}
-+
-+static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
-+{
-+ int i;
-+ u8 data[3], tmp;
-+
-+ data[0] = phy;
-+ data[1] = reg & 0xff;
-+ data[2] = (reg >> 8) & 0xff;
-+ tmp = indx | PHY_WRITE | PHY_GO;
-+ i = 0;
-+
-+ set_registers(dev, PHYADD, sizeof(data), data);
-+ set_registers(dev, PHYCNT, 1, &tmp);
-+ do {
-+ get_registers(dev, PHYCNT, 1, data);
-+ } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
-+
-+ if (i <= MII_TIMEOUT)
-+ return 0;
-+ else
-+ return 1;
-+}
-+
-+static inline void set_ethernet_addr(rtl8150_t * dev)
-+{
-+ u8 node_id[6];
-+
-+ get_registers(dev, IDR, sizeof(node_id), node_id);
-+ memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
-+}
-+
-+static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
-+{
-+ struct sockaddr *addr = p;
-+ rtl8150_t *dev = netdev_priv(netdev);
-+
-+ if (netif_running(netdev))
-+ return -EBUSY;
-+
-+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-+ netdev_dbg(netdev, "Setting MAC address to %pM\n", netdev->dev_addr);
-+ /* Set the IDR registers. */
-+ set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
-+#ifdef EEPROM_WRITE
-+ {
-+ int i;
-+ u8 cr;
-+ /* Get the CR contents. */
-+ get_registers(dev, CR, 1, &cr);
-+ /* Set the WEPROM bit (eeprom write enable). */
-+ cr |= 0x20;
-+ set_registers(dev, CR, 1, &cr);
-+ /* Write the MAC address into eeprom. Eeprom writes must be word-sized,
-+ so we need to split them up. */
-+ for (i = 0; i * 2 < netdev->addr_len; i++) {
-+ set_registers(dev, IDR_EEPROM + (i * 2), 2,
-+ netdev->dev_addr + (i * 2));
-+ }
-+ /* Clear the WEPROM bit (preventing accidental eeprom writes). */
-+ cr &= 0xdf;
-+ set_registers(dev, CR, 1, &cr);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+static int rtl8150_reset(rtl8150_t * dev)
-+{
-+ u8 data = 0x10;
-+ int i = HZ;
-+
-+ set_registers(dev, CR, 1, &data);
-+ do {
-+ get_registers(dev, CR, 1, &data);
-+ } while ((data & 0x10) && --i);
-+
-+ return (i > 0) ? 1 : 0;
-+}
-+
-+static int alloc_all_urbs(rtl8150_t * dev)
-+{
-+ dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!dev->rx_urb)
-+ return 0;
-+ dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!dev->tx_urb) {
-+ usb_free_urb(dev->rx_urb);
-+ return 0;
-+ }
-+ dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-+ if (!dev->intr_urb) {
-+ usb_free_urb(dev->rx_urb);
-+ usb_free_urb(dev->tx_urb);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static void free_all_urbs(rtl8150_t * dev)
-+{
-+ usb_free_urb(dev->rx_urb);
-+ usb_free_urb(dev->tx_urb);
-+ usb_free_urb(dev->intr_urb);
-+}
-+
-+static void unlink_all_urbs(rtl8150_t * dev)
-+{
-+ usb_kill_urb(dev->rx_urb);
-+ usb_kill_urb(dev->tx_urb);
-+ usb_kill_urb(dev->intr_urb);
-+}
-+
-+static inline struct sk_buff *pull_skb(rtl8150_t *dev)
-+{
-+ struct sk_buff *skb;
-+ int i;
-+
-+ for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
-+ if (dev->rx_skb_pool[i]) {
-+ skb = dev->rx_skb_pool[i];
-+ dev->rx_skb_pool[i] = NULL;
-+ return skb;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static void read_bulk_callback(struct urb *urb)
-+{
-+ rtl8150_t *dev;
-+ unsigned pkt_len, res;
-+ struct sk_buff *skb;
-+ struct net_device *netdev;
-+ u16 rx_stat;
-+ int status = urb->status;
-+ int result;
-+
-+ dev = urb->context;
-+ if (!dev)
-+ return;
-+ if (test_bit(RTL8150_UNPLUG, &dev->flags))
-+ return;
-+ netdev = dev->netdev;
-+ if (!netif_device_present(netdev))
-+ return;
-+
-+ switch (status) {
-+ case 0:
-+ break;
-+ case -ENOENT:
-+ return; /* the urb is in unlink state */
-+ case -ETIME:
-+ if (printk_ratelimit())
-+ dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
-+ goto goon;
-+ default:
-+ if (printk_ratelimit())
-+ dev_warn(&urb->dev->dev, "Rx status %d\n", status);
-+ goto goon;
-+ }
-+
-+ if (!dev->rx_skb)
-+ goto resched;
-+ /* protect against short packets (tell me why we got some?!?) */
-+ if (urb->actual_length < 4)
-+ goto goon;
-+
-+ res = urb->actual_length;
-+ rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4));
-+ pkt_len = res - 4;
-+
-+ skb_put(dev->rx_skb, pkt_len);
-+ dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
-+ netif_rx(dev->rx_skb);
-+ netdev->stats.rx_packets++;
-+ netdev->stats.rx_bytes += pkt_len;
-+
-+ spin_lock(&dev->rx_pool_lock);
-+ skb = pull_skb(dev);
-+ spin_unlock(&dev->rx_pool_lock);
-+ if (!skb)
-+ goto resched;
-+
-+ dev->rx_skb = skb;
-+goon:
-+ usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
-+ dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-+ result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
-+ if (result == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ else if (result) {
-+ set_bit(RX_URB_FAIL, &dev->flags);
-+ goto resched;
-+ } else {
-+ clear_bit(RX_URB_FAIL, &dev->flags);
-+ }
-+
-+ return;
-+resched:
-+ tasklet_schedule(&dev->tl);
-+}
-+
-+static void write_bulk_callback(struct urb *urb)
-+{
-+ rtl8150_t *dev;
-+ int status = urb->status;
-+
-+ dev = urb->context;
-+ if (!dev)
-+ return;
-+ dev_kfree_skb_irq(dev->tx_skb);
-+ if (!netif_device_present(dev->netdev))
-+ return;
-+ if (status)
-+ dev_info(&urb->dev->dev, "%s: Tx status %d\n",
-+ dev->netdev->name, status);
-+ dev->netdev->trans_start = jiffies;
-+ netif_wake_queue(dev->netdev);
-+}
-+
-+static void intr_callback(struct urb *urb)
-+{
-+ rtl8150_t *dev;
-+ __u8 *d;
-+ int status = urb->status;
-+ int res;
-+
-+ dev = urb->context;
-+ if (!dev)
-+ return;
-+ switch (status) {
-+ case 0: /* success */
-+ break;
-+ case -ECONNRESET: /* unlink */
-+ case -ENOENT:
-+ case -ESHUTDOWN:
-+ return;
-+ /* -EPIPE: should clear the halt */
-+ default:
-+ dev_info(&urb->dev->dev, "%s: intr status %d\n",
-+ dev->netdev->name, status);
-+ goto resubmit;
-+ }
-+
-+ d = urb->transfer_buffer;
-+ if (d[0] & TSR_ERRORS) {
-+ dev->netdev->stats.tx_errors++;
-+ if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))
-+ dev->netdev->stats.tx_aborted_errors++;
-+ if (d[INT_TSR] & TSR_LCOL)
-+ dev->netdev->stats.tx_window_errors++;
-+ if (d[INT_TSR] & TSR_LOSS_CRS)
-+ dev->netdev->stats.tx_carrier_errors++;
-+ }
-+ /* Report link status changes to the network stack */
-+ if ((d[INT_MSR] & MSR_LINK) == 0) {
-+ if (netif_carrier_ok(dev->netdev)) {
-+ netif_carrier_off(dev->netdev);
-+ netdev_dbg(dev->netdev, "%s: LINK LOST\n", __func__);
-+ }
-+ } else {
-+ if (!netif_carrier_ok(dev->netdev)) {
-+ netif_carrier_on(dev->netdev);
-+ netdev_dbg(dev->netdev, "%s: LINK CAME BACK\n", __func__);
-+ }
-+ }
-+
-+resubmit:
-+ res = usb_submit_urb (urb, GFP_ATOMIC);
-+ if (res == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ else if (res)
-+ dev_err(&dev->udev->dev,
-+ "can't resubmit intr, %s-%s/input0, status %d\n",
-+ dev->udev->bus->bus_name, dev->udev->devpath, res);
-+}
-+
-+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ rtl8150_t *dev = usb_get_intfdata(intf);
-+
-+ netif_device_detach(dev->netdev);
-+
-+ if (netif_running(dev->netdev)) {
-+ usb_kill_urb(dev->rx_urb);
-+ usb_kill_urb(dev->intr_urb);
-+ }
-+ return 0;
-+}
-+
-+static int rtl8150_resume(struct usb_interface *intf)
-+{
-+ rtl8150_t *dev = usb_get_intfdata(intf);
-+
-+ netif_device_attach(dev->netdev);
-+ if (netif_running(dev->netdev)) {
-+ dev->rx_urb->status = 0;
-+ dev->rx_urb->actual_length = 0;
-+ read_bulk_callback(dev->rx_urb);
-+
-+ dev->intr_urb->status = 0;
-+ dev->intr_urb->actual_length = 0;
-+ intr_callback(dev->intr_urb);
-+ }
-+ return 0;
-+}
-+
-+/*
-+**
-+** network related part of the code
-+**
-+*/
-+
-+static void fill_skb_pool(rtl8150_t *dev)
-+{
-+ struct sk_buff *skb;
-+ int i;
-+
-+ for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
-+ if (dev->rx_skb_pool[i])
-+ continue;
-+ skb = dev_alloc_skb(RTL8150_MTU + 2);
-+ if (!skb) {
-+ return;
-+ }
-+ skb_reserve(skb, 2);
-+ dev->rx_skb_pool[i] = skb;
-+ }
-+}
-+
-+static void free_skb_pool(rtl8150_t *dev)
-+{
-+ int i;
-+
-+ for (i = 0; i < RX_SKB_POOL_SIZE; i++)
-+ if (dev->rx_skb_pool[i])
-+ dev_kfree_skb(dev->rx_skb_pool[i]);
-+}
-+
-+static void rx_fixup(unsigned long data)
-+{
-+ struct rtl8150 *dev = (struct rtl8150 *)data;
-+ struct sk_buff *skb;
-+ int status;
-+
-+ spin_lock_irq(&dev->rx_pool_lock);
-+ fill_skb_pool(dev);
-+ spin_unlock_irq(&dev->rx_pool_lock);
-+ if (test_bit(RX_URB_FAIL, &dev->flags))
-+ if (dev->rx_skb)
-+ goto try_again;
-+ spin_lock_irq(&dev->rx_pool_lock);
-+ skb = pull_skb(dev);
-+ spin_unlock_irq(&dev->rx_pool_lock);
-+ if (skb == NULL)
-+ goto tlsched;
-+ dev->rx_skb = skb;
-+ usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
-+ dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-+try_again:
-+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
-+ if (status == -ENODEV) {
-+ netif_device_detach(dev->netdev);
-+ } else if (status) {
-+ set_bit(RX_URB_FAIL, &dev->flags);
-+ goto tlsched;
-+ } else {
-+ clear_bit(RX_URB_FAIL, &dev->flags);
-+ }
-+
-+ return;
-+tlsched:
-+ tasklet_schedule(&dev->tl);
-+}
-+
-+static int enable_net_traffic(rtl8150_t * dev)
-+{
-+ u8 cr, tcr, rcr, msr;
-+
-+ if (!rtl8150_reset(dev)) {
-+ dev_warn(&dev->udev->dev, "device reset failed\n");
-+ }
-+ /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
-+ rcr = 0x9e;
-+ tcr = 0xd8;
-+ cr = 0x0c;
-+ if (!(rcr & 0x80))
-+ set_bit(RTL8150_HW_CRC, &dev->flags);
-+ set_registers(dev, RCR, 1, &rcr);
-+ set_registers(dev, TCR, 1, &tcr);
-+ set_registers(dev, CR, 1, &cr);
-+ get_registers(dev, MSR, 1, &msr);
-+
-+ return 0;
-+}
-+
-+static void disable_net_traffic(rtl8150_t * dev)
-+{
-+ u8 cr;
-+
-+ get_registers(dev, CR, 1, &cr);
-+ cr &= 0xf3;
-+ set_registers(dev, CR, 1, &cr);
-+}
-+
-+static void rtl8150_tx_timeout(struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ dev_warn(&netdev->dev, "Tx timeout.\n");
-+ usb_unlink_urb(dev->tx_urb);
-+ netdev->stats.tx_errors++;
-+}
-+
-+static void rtl8150_set_multicast(struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ u16 rx_creg = 0x9e;
-+
-+ netif_stop_queue(netdev);
-+ if (netdev->flags & IFF_PROMISC) {
-+ rx_creg |= 0x0001;
-+ dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
-+ } else if (!netdev_mc_empty(netdev) ||
-+ (netdev->flags & IFF_ALLMULTI)) {
-+ rx_creg &= 0xfffe;
-+ rx_creg |= 0x0002;
-+ dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name);
-+ } else {
-+ /* ~RX_MULTICAST, ~RX_PROMISCUOUS */
-+ rx_creg &= 0x00fc;
-+ }
-+ async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg);
-+ netif_wake_queue(netdev);
-+}
-+
-+static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
-+ struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ int count, res;
-+
-+ netif_stop_queue(netdev);
-+ count = (skb->len < 60) ? 60 : skb->len;
-+ count = (count & 0x3f) ? count : count + 1;
-+ dev->tx_skb = skb;
-+ usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
-+ skb->data, count, write_bulk_callback, dev);
-+ if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
-+ /* Can we get/handle EPIPE here? */
-+ if (res == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ else {
-+ dev_warn(&netdev->dev, "failed tx_urb %d\n", res);
-+ netdev->stats.tx_errors++;
-+ netif_start_queue(netdev);
-+ }
-+ } else {
-+ netdev->stats.tx_packets++;
-+ netdev->stats.tx_bytes += skb->len;
-+ netdev->trans_start = jiffies;
-+ }
-+
-+ return NETDEV_TX_OK;
-+}
-+
-+
-+static void set_carrier(struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ short tmp;
-+
-+ get_registers(dev, CSCR, 2, &tmp);
-+ if (tmp & CSCR_LINK_STATUS)
-+ netif_carrier_on(netdev);
-+ else
-+ netif_carrier_off(netdev);
-+}
-+
-+static int rtl8150_open(struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ int res;
-+
-+ if (dev->rx_skb == NULL)
-+ dev->rx_skb = pull_skb(dev);
-+ if (!dev->rx_skb)
-+ return -ENOMEM;
-+
-+ set_registers(dev, IDR, 6, netdev->dev_addr);
-+
-+ usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
-+ dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-+ if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
-+ if (res == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res);
-+ return res;
-+ }
-+ usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
-+ dev->intr_buff, INTBUFSIZE, intr_callback,
-+ dev, dev->intr_interval);
-+ if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
-+ if (res == -ENODEV)
-+ netif_device_detach(dev->netdev);
-+ dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res);
-+ usb_kill_urb(dev->rx_urb);
-+ return res;
-+ }
-+ enable_net_traffic(dev);
-+ set_carrier(netdev);
-+ netif_start_queue(netdev);
-+
-+ return res;
-+}
-+
-+static int rtl8150_close(struct net_device *netdev)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+
-+ netif_stop_queue(netdev);
-+ if (!test_bit(RTL8150_UNPLUG, &dev->flags))
-+ disable_net_traffic(dev);
-+ unlink_all_urbs(dev);
-+
-+ return 0;
-+}
-+
-+static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+
-+ strlcpy(info->driver, driver_name, sizeof(info->driver));
-+ strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
-+ usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
-+}
-+
-+static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ short lpa, bmcr;
-+
-+ ecmd->supported = (SUPPORTED_10baseT_Half |
-+ SUPPORTED_10baseT_Full |
-+ SUPPORTED_100baseT_Half |
-+ SUPPORTED_100baseT_Full |
-+ SUPPORTED_Autoneg |
-+ SUPPORTED_TP | SUPPORTED_MII);
-+ ecmd->port = PORT_TP;
-+ ecmd->transceiver = XCVR_INTERNAL;
-+ ecmd->phy_address = dev->phy;
-+ get_registers(dev, BMCR, 2, &bmcr);
-+ get_registers(dev, ANLP, 2, &lpa);
-+ if (bmcr & BMCR_ANENABLE) {
-+ u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ?
-+ SPEED_100 : SPEED_10);
-+ ethtool_cmd_speed_set(ecmd, speed);
-+ ecmd->autoneg = AUTONEG_ENABLE;
-+ if (speed == SPEED_100)
-+ ecmd->duplex = (lpa & LPA_100FULL) ?
-+ DUPLEX_FULL : DUPLEX_HALF;
-+ else
-+ ecmd->duplex = (lpa & LPA_10FULL) ?
-+ DUPLEX_FULL : DUPLEX_HALF;
-+ } else {
-+ ecmd->autoneg = AUTONEG_DISABLE;
-+ ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ?
-+ SPEED_100 : SPEED_10));
-+ ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?
-+ DUPLEX_FULL : DUPLEX_HALF;
-+ }
-+ return 0;
-+}
-+
-+static const struct ethtool_ops ops = {
-+ .get_drvinfo = rtl8150_get_drvinfo,
-+ .get_settings = rtl8150_get_settings,
-+ .get_link = ethtool_op_get_link
-+};
-+
-+static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-+{
-+ rtl8150_t *dev = netdev_priv(netdev);
-+ u16 *data = (u16 *) & rq->ifr_ifru;
-+ int res = 0;
-+
-+ switch (cmd) {
-+ case SIOCDEVPRIVATE:
-+ data[0] = dev->phy;
-+ case SIOCDEVPRIVATE + 1:
-+ read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
-+ break;
-+ case SIOCDEVPRIVATE + 2:
-+ if (!capable(CAP_NET_ADMIN))
-+ return -EPERM;
-+ write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
-+ break;
-+ default:
-+ res = -EOPNOTSUPP;
-+ }
-+
-+ return res;
-+}
-+
-+static const struct net_device_ops rtl8150_netdev_ops = {
-+ .ndo_open = rtl8150_open,
-+ .ndo_stop = rtl8150_close,
-+ .ndo_do_ioctl = rtl8150_ioctl,
-+ .ndo_start_xmit = rtl8150_start_xmit,
-+ .ndo_tx_timeout = rtl8150_tx_timeout,
-+ .ndo_set_rx_mode = rtl8150_set_multicast,
-+ .ndo_set_mac_address = rtl8150_set_mac_address,
-+
-+ .ndo_change_mtu = eth_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+};
-+
-+static int rtl8150_probe(struct usb_interface *intf,
-+ const struct usb_device_id *id)
-+{
-+ struct usb_device *udev = interface_to_usbdev(intf);
-+ rtl8150_t *dev;
-+ struct net_device *netdev;
-+
-+ netdev = alloc_etherdev(sizeof(rtl8150_t));
-+ if (!netdev)
-+ return -ENOMEM;
-+
-+ dev = netdev_priv(netdev);
-+
-+ dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
-+ if (!dev->intr_buff) {
-+ free_netdev(netdev);
-+ return -ENOMEM;
-+ }
-+
-+ tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
-+ spin_lock_init(&dev->rx_pool_lock);
-+
-+ dev->udev = udev;
-+ dev->netdev = netdev;
-+ netdev->netdev_ops = &rtl8150_netdev_ops;
-+ netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
-+ netdev->ethtool_ops = &ops;
-+ dev->intr_interval = 100; /* 100ms */
-+
-+ if (!alloc_all_urbs(dev)) {
-+ dev_err(&intf->dev, "out of memory\n");
-+ goto out;
-+ }
-+ if (!rtl8150_reset(dev)) {
-+ dev_err(&intf->dev, "couldn't reset the device\n");
-+ goto out1;
-+ }
-+ fill_skb_pool(dev);
-+ set_ethernet_addr(dev);
-+
-+ usb_set_intfdata(intf, dev);
-+ SET_NETDEV_DEV(netdev, &intf->dev);
-+ if (register_netdev(netdev) != 0) {
-+ dev_err(&intf->dev, "couldn't register the device\n");
-+ goto out2;
-+ }
-+
-+ dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name);
-+
-+ return 0;
-+
-+out2:
-+ usb_set_intfdata(intf, NULL);
-+ free_skb_pool(dev);
-+out1:
-+ free_all_urbs(dev);
-+out:
-+ kfree(dev->intr_buff);
-+ free_netdev(netdev);
-+ return -EIO;
-+}
-+
-+static void rtl8150_disconnect(struct usb_interface *intf)
-+{
-+ rtl8150_t *dev = usb_get_intfdata(intf);
-+
-+ usb_set_intfdata(intf, NULL);
-+ if (dev) {
-+ set_bit(RTL8150_UNPLUG, &dev->flags);
-+ tasklet_kill(&dev->tl);
-+ unregister_netdev(dev->netdev);
-+ unlink_all_urbs(dev);
-+ free_all_urbs(dev);
-+ free_skb_pool(dev);
-+ if (dev->rx_skb)
-+ dev_kfree_skb(dev->rx_skb);
-+ kfree(dev->intr_buff);
-+ free_netdev(dev->netdev);
-+ }
-+}
-+
-+static struct usb_driver rtl8150_driver = {
-+ .name = driver_name,
-+ .probe = rtl8150_probe,
-+ .disconnect = rtl8150_disconnect,
-+ .id_table = rtl8150_table,
-+ .suspend = rtl8150_suspend,
-+ .resume = rtl8150_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(rtl8150_driver);
-+
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/smsc75xx.c backports-4.2.6-1/drivers/net/usb/smsc75xx.c
---- backports-4.2.6-1.org/drivers/net/usb/smsc75xx.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/smsc75xx.c 2016-06-28 14:35:18.008640551 +0200
-@@ -0,0 +1,2286 @@
-+ /***************************************************************************
-+ *
-+ * Copyright (C) 2007-2010 SMSC
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ *****************************************************************************/
-+
-+#include <linux/module.h>
-+#include <linux/kmod.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/bitrev.h>
-+#include <linux/crc16.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+#include "smsc75xx.h"
-+
-+#define SMSC_CHIPNAME "smsc75xx"
-+#define SMSC_DRIVER_VERSION "1.0.0"
-+#define HS_USB_PKT_SIZE (512)
-+#define FS_USB_PKT_SIZE (64)
-+#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
-+#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE)
-+#define DEFAULT_BULK_IN_DELAY (0x00002000)
-+#define MAX_SINGLE_PACKET_SIZE (9000)
-+#define LAN75XX_EEPROM_MAGIC (0x7500)
-+#define EEPROM_MAC_OFFSET (0x01)
-+#define DEFAULT_TX_CSUM_ENABLE (true)
-+#define DEFAULT_RX_CSUM_ENABLE (true)
-+#define SMSC75XX_INTERNAL_PHY_ID (1)
-+#define SMSC75XX_TX_OVERHEAD (8)
-+#define MAX_RX_FIFO_SIZE (20 * 1024)
-+#define MAX_TX_FIFO_SIZE (12 * 1024)
-+#define USB_VENDOR_ID_SMSC (0x0424)
-+#define USB_PRODUCT_ID_LAN7500 (0x7500)
-+#define USB_PRODUCT_ID_LAN7505 (0x7505)
-+#define RXW_PADDING 2
-+#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
-+ WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
-+
-+#define SUSPEND_SUSPEND0 (0x01)
-+#define SUSPEND_SUSPEND1 (0x02)
-+#define SUSPEND_SUSPEND2 (0x04)
-+#define SUSPEND_SUSPEND3 (0x08)
-+#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
-+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
-+
-+struct smsc75xx_priv {
-+ struct usbnet *dev;
-+ u32 rfe_ctl;
-+ u32 wolopts;
-+ u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
-+ struct mutex dataport_mutex;
-+ spinlock_t rfe_ctl_lock;
-+ struct work_struct set_multicast;
-+ u8 suspend_flags;
-+};
-+
-+struct usb_context {
-+ struct usb_ctrlrequest req;
-+ struct usbnet *dev;
-+};
-+
-+static bool turbo_mode = true;
-+module_param(turbo_mode, bool, 0644);
-+MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-+
-+static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index,
-+ u32 *data, int in_pm)
-+{
-+ u32 buf;
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_read_cmd;
-+ else
-+ fn = usbnet_read_cmd_nopm;
-+
-+ ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
-+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, index, &buf, 4);
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
-+ index, ret);
-+
-+ le32_to_cpus(&buf);
-+ *data = buf;
-+
-+ return ret;
-+}
-+
-+static int __must_check __smsc75xx_write_reg(struct usbnet *dev, u32 index,
-+ u32 data, int in_pm)
-+{
-+ u32 buf;
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_write_cmd;
-+ else
-+ fn = usbnet_write_cmd_nopm;
-+
-+ buf = data;
-+ cpu_to_le32s(&buf);
-+
-+ ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
-+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, index, &buf, 4);
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n",
-+ index, ret);
-+
-+ return ret;
-+}
-+
-+static int __must_check smsc75xx_read_reg_nopm(struct usbnet *dev, u32 index,
-+ u32 *data)
-+{
-+ return __smsc75xx_read_reg(dev, index, data, 1);
-+}
-+
-+static int __must_check smsc75xx_write_reg_nopm(struct usbnet *dev, u32 index,
-+ u32 data)
-+{
-+ return __smsc75xx_write_reg(dev, index, data, 1);
-+}
-+
-+static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index,
-+ u32 *data)
-+{
-+ return __smsc75xx_read_reg(dev, index, data, 0);
-+}
-+
-+static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index,
-+ u32 data)
-+{
-+ return __smsc75xx_write_reg(dev, index, data, 0);
-+}
-+
-+/* Loop until the read is completed with timeout
-+ * called with phy_mutex held */
-+static __must_check int __smsc75xx_phy_wait_not_busy(struct usbnet *dev,
-+ int in_pm)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = __smsc75xx_read_reg(dev, MII_ACCESS, &val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_ACCESS\n");
-+ return ret;
-+ }
-+
-+ if (!(val & MII_ACCESS_BUSY))
-+ return 0;
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ return -EIO;
-+}
-+
-+static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
-+ int in_pm)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u32 val, addr;
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ /* confirm MII not busy */
-+ ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_read\n");
-+ goto done;
-+ }
-+
-+ /* set the address, index & direction (read from PHY) */
-+ phy_id &= dev->mii.phy_id_mask;
-+ idx &= dev->mii.reg_num_mask;
-+ addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
-+ | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
-+ | MII_ACCESS_READ | MII_ACCESS_BUSY;
-+ ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_ACCESS\n");
-+ goto done;
-+ }
-+
-+ ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
-+ goto done;
-+ }
-+
-+ ret = __smsc75xx_read_reg(dev, MII_DATA, &val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_DATA\n");
-+ goto done;
-+ }
-+
-+ ret = (u16)(val & 0xFFFF);
-+
-+done:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id,
-+ int idx, int regval, int in_pm)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u32 val, addr;
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ /* confirm MII not busy */
-+ ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_write\n");
-+ goto done;
-+ }
-+
-+ val = regval;
-+ ret = __smsc75xx_write_reg(dev, MII_DATA, val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_DATA\n");
-+ goto done;
-+ }
-+
-+ /* set the address, index & direction (write to PHY) */
-+ phy_id &= dev->mii.phy_id_mask;
-+ idx &= dev->mii.reg_num_mask;
-+ addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR)
-+ | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR)
-+ | MII_ACCESS_WRITE | MII_ACCESS_BUSY;
-+ ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_ACCESS\n");
-+ goto done;
-+ }
-+
-+ ret = __smsc75xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
-+ goto done;
-+ }
-+
-+done:
-+ mutex_unlock(&dev->phy_mutex);
-+}
-+
-+static int smsc75xx_mdio_read_nopm(struct net_device *netdev, int phy_id,
-+ int idx)
-+{
-+ return __smsc75xx_mdio_read(netdev, phy_id, idx, 1);
-+}
-+
-+static void smsc75xx_mdio_write_nopm(struct net_device *netdev, int phy_id,
-+ int idx, int regval)
-+{
-+ __smsc75xx_mdio_write(netdev, phy_id, idx, regval, 1);
-+}
-+
-+static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
-+{
-+ return __smsc75xx_mdio_read(netdev, phy_id, idx, 0);
-+}
-+
-+static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
-+ int regval)
-+{
-+ __smsc75xx_mdio_write(netdev, phy_id, idx, regval, 0);
-+}
-+
-+static int smsc75xx_wait_eeprom(struct usbnet *dev)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT))
-+ break;
-+ udelay(40);
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) {
-+ netdev_warn(dev->net, "EEPROM read operation timeout\n");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = smsc75xx_read_reg(dev, E2P_CMD, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ if (!(val & E2P_CMD_BUSY))
-+ return 0;
-+
-+ udelay(40);
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ netdev_warn(dev->net, "EEPROM is busy\n");
-+ return -EIO;
-+}
-+
-+static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
-+ u8 *data)
-+{
-+ u32 val;
-+ int i, ret;
-+
-+ BUG_ON(!dev);
-+ BUG_ON(!data);
-+
-+ ret = smsc75xx_eeprom_confirm_not_busy(dev);
-+ if (ret)
-+ return ret;
-+
-+ for (i = 0; i < length; i++) {
-+ val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR);
-+ ret = smsc75xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc75xx_read_reg(dev, E2P_DATA, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_DATA\n");
-+ return ret;
-+ }
-+
-+ data[i] = val & 0xFF;
-+ offset++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
-+ u8 *data)
-+{
-+ u32 val;
-+ int i, ret;
-+
-+ BUG_ON(!dev);
-+ BUG_ON(!data);
-+
-+ ret = smsc75xx_eeprom_confirm_not_busy(dev);
-+ if (ret)
-+ return ret;
-+
-+ /* Issue write/erase enable command */
-+ val = E2P_CMD_BUSY | E2P_CMD_EWEN;
-+ ret = smsc75xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ for (i = 0; i < length; i++) {
-+
-+ /* Fill data register */
-+ val = data[i];
-+ ret = smsc75xx_write_reg(dev, E2P_DATA, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_DATA\n");
-+ return ret;
-+ }
-+
-+ /* Send "write" command */
-+ val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR);
-+ ret = smsc75xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ offset++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev)
-+{
-+ int i, ret;
-+
-+ for (i = 0; i < 100; i++) {
-+ u32 dp_sel;
-+ ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading DP_SEL\n");
-+ return ret;
-+ }
-+
-+ if (dp_sel & DP_SEL_DPRDY)
-+ return 0;
-+
-+ udelay(40);
-+ }
-+
-+ netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out\n");
-+
-+ return -EIO;
-+}
-+
-+static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr,
-+ u32 length, u32 *buf)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 dp_sel;
-+ int i, ret;
-+
-+ mutex_lock(&pdata->dataport_mutex);
-+
-+ ret = smsc75xx_dataport_wait_not_busy(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "smsc75xx_dataport_write busy on entry\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading DP_SEL\n");
-+ goto done;
-+ }
-+
-+ dp_sel &= ~DP_SEL_RSEL;
-+ dp_sel |= ram_select;
-+ ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing DP_SEL\n");
-+ goto done;
-+ }
-+
-+ for (i = 0; i < length; i++) {
-+ ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing DP_ADDR\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing DP_DATA\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing DP_CMD\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_dataport_wait_not_busy(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "smsc75xx_dataport_write timeout\n");
-+ goto done;
-+ }
-+ }
-+
-+done:
-+ mutex_unlock(&pdata->dataport_mutex);
-+ return ret;
-+}
-+
-+/* returns hash bit number for given MAC address */
-+static u32 smsc75xx_hash(char addr[ETH_ALEN])
-+{
-+ return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff;
-+}
-+
-+static void smsc75xx_deferred_multicast_write(struct work_struct *param)
-+{
-+ struct smsc75xx_priv *pdata =
-+ container_of(param, struct smsc75xx_priv, set_multicast);
-+ struct usbnet *dev = pdata->dev;
-+ int ret;
-+
-+ netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n",
-+ pdata->rfe_ctl);
-+
-+ smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN,
-+ DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table);
-+
-+ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "Error writing RFE_CRL\n");
-+}
-+
-+static void smsc75xx_set_multicast(struct net_device *netdev)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ unsigned long flags;
-+ int i;
-+
-+ spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
-+
-+ pdata->rfe_ctl &=
-+ ~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF);
-+ pdata->rfe_ctl |= RFE_CTL_AB;
-+
-+ for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++)
-+ pdata->multicast_hash_table[i] = 0;
-+
-+ if (dev->net->flags & IFF_PROMISC) {
-+ netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n");
-+ pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU;
-+ } else if (dev->net->flags & IFF_ALLMULTI) {
-+ netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n");
-+ pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF;
-+ } else if (!netdev_mc_empty(dev->net)) {
-+ struct netdev_hw_addr *ha;
-+
-+ netif_dbg(dev, drv, dev->net, "receive multicast hash filter\n");
-+
-+ pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF;
-+
-+ netdev_for_each_mc_addr(ha, netdev) {
-+ u32 bitnum = smsc75xx_hash(ha->addr);
-+ pdata->multicast_hash_table[bitnum / 32] |=
-+ (1 << (bitnum % 32));
-+ }
-+ } else {
-+ netif_dbg(dev, drv, dev->net, "receive own packets only\n");
-+ pdata->rfe_ctl |= RFE_CTL_DPF;
-+ }
-+
-+ spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
-+
-+ /* defer register writes to a sleepable context */
-+ schedule_work(&pdata->set_multicast);
-+}
-+
-+static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
-+ u16 lcladv, u16 rmtadv)
-+{
-+ u32 flow = 0, fct_flow = 0;
-+ int ret;
-+
-+ if (duplex == DUPLEX_FULL) {
-+ u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
-+
-+ if (cap & FLOW_CTRL_TX) {
-+ flow = (FLOW_TX_FCEN | 0xFFFF);
-+ /* set fct_flow thresholds to 20% and 80% */
-+ fct_flow = (8 << 8) | 32;
-+ }
-+
-+ if (cap & FLOW_CTRL_RX)
-+ flow |= FLOW_RX_FCEN;
-+
-+ netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n",
-+ (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
-+ (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
-+ } else {
-+ netif_dbg(dev, link, dev->net, "half duplex\n");
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, FLOW, flow);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing FLOW\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing FCT_FLOW\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_link_reset(struct usbnet *dev)
-+{
-+ struct mii_if_info *mii = &dev->mii;
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+ u16 lcladv, rmtadv;
-+ int ret;
-+
-+ /* write to clear phy interrupt status */
-+ smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC,
-+ PHY_INT_SRC_CLEAR_ALL);
-+
-+ ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing INT_STS\n");
-+ return ret;
-+ }
-+
-+ mii_check_media(mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
-+ rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
-+
-+ netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
-+ ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
-+
-+ return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
-+}
-+
-+static void smsc75xx_status(struct usbnet *dev, struct urb *urb)
-+{
-+ u32 intdata;
-+
-+ if (urb->actual_length != 4) {
-+ netdev_warn(dev->net, "unexpected urb length %d\n",
-+ urb->actual_length);
-+ return;
-+ }
-+
-+ memcpy(&intdata, urb->transfer_buffer, 4);
-+ le32_to_cpus(&intdata);
-+
-+ netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata);
-+
-+ if (intdata & INT_ENP_PHY_INT)
-+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
-+ else
-+ netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n",
-+ intdata);
-+}
-+
-+static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)
-+{
-+ return MAX_EEPROM_SIZE;
-+}
-+
-+static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev,
-+ struct ethtool_eeprom *ee, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ ee->magic = LAN75XX_EEPROM_MAGIC;
-+
-+ return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data);
-+}
-+
-+static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
-+ struct ethtool_eeprom *ee, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ if (ee->magic != LAN75XX_EEPROM_MAGIC) {
-+ netdev_warn(dev->net, "EEPROM: magic value mismatch: 0x%x\n",
-+ ee->magic);
-+ return -EINVAL;
-+ }
-+
-+ return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
-+}
-+
-+static void smsc75xx_ethtool_get_wol(struct net_device *net,
-+ struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+
-+ wolinfo->supported = SUPPORTED_WAKE;
-+ wolinfo->wolopts = pdata->wolopts;
-+}
-+
-+static int smsc75xx_ethtool_set_wol(struct net_device *net,
-+ struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ int ret;
-+
-+ pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
-+
-+ ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct ethtool_ops smsc75xx_ethtool_ops = {
-+ .get_link = usbnet_get_link,
-+ .nway_reset = usbnet_nway_reset,
-+ .get_drvinfo = usbnet_get_drvinfo,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len,
-+ .get_eeprom = smsc75xx_ethtool_get_eeprom,
-+ .set_eeprom = smsc75xx_ethtool_set_eeprom,
-+ .get_wol = smsc75xx_ethtool_get_wol,
-+ .set_wol = smsc75xx_ethtool_set_wol,
-+};
-+
-+static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ if (!netif_running(netdev))
-+ return -EINVAL;
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static void smsc75xx_init_mac_address(struct usbnet *dev)
-+{
-+ /* try reading mac address from EEPROM */
-+ if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
-+ dev->net->dev_addr) == 0) {
-+ if (is_valid_ether_addr(dev->net->dev_addr)) {
-+ /* eeprom values are valid so use them */
-+ netif_dbg(dev, ifup, dev->net,
-+ "MAC address read from EEPROM\n");
-+ return;
-+ }
-+ }
-+
-+ /* no eeprom, or eeprom values are invalid. generate random MAC */
-+ eth_hw_addr_random(dev->net);
-+ netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
-+}
-+
-+static int smsc75xx_set_mac_address(struct usbnet *dev)
-+{
-+ u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
-+ dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
-+ u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
-+
-+ int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write RX_ADDRH: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write RX_ADDRL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ addr_hi |= ADDR_FILTX_FB_VALID;
-+ ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write ADDR_FILTX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "Failed to write ADDR_FILTX+4: %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static int smsc75xx_phy_initialize(struct usbnet *dev)
-+{
-+ int bmcr, ret, timeout = 0;
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = smsc75xx_mdio_read;
-+ dev->mii.mdio_write = smsc75xx_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.supports_gmii = 1;
-+ dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID;
-+
-+ /* reset phy and wait for reset to complete */
-+ smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+
-+ do {
-+ msleep(10);
-+ bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
-+ if (bmcr < 0) {
-+ netdev_warn(dev->net, "Error reading MII_BMCR\n");
-+ return bmcr;
-+ }
-+ timeout++;
-+ } while ((bmcr & BMCR_RESET) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout on PHY Reset\n");
-+ return -EIO;
-+ }
-+
-+ smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
-+ ADVERTISE_PAUSE_ASYM);
-+ smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
-+ ADVERTISE_1000FULL);
-+
-+ /* read and write to clear phy interrupt status */
-+ ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
-+ return ret;
-+ }
-+
-+ smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff);
-+
-+ smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
-+ PHY_INT_MASK_DEFAULT);
-+ mii_nway_restart(&dev->mii);
-+
-+ netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
-+ return 0;
-+}
-+
-+static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
-+{
-+ int ret = 0;
-+ u32 buf;
-+ bool rxenabled;
-+
-+ ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ rxenabled = ((buf & MAC_RX_RXEN) != 0);
-+
-+ if (rxenabled) {
-+ buf &= ~MAC_RX_RXEN;
-+ ret = smsc75xx_write_reg(dev, MAC_RX, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ /* add 4 to size for FCS */
-+ buf &= ~MAC_RX_MAX_SIZE;
-+ buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE);
-+
-+ ret = smsc75xx_write_reg(dev, MAC_RX, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ if (rxenabled) {
-+ buf |= MAC_RX_RXEN;
-+ ret = smsc75xx_write_reg(dev, MAC_RX, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ int ret;
-+
-+ if (new_mtu > MAX_SINGLE_PACKET_SIZE)
-+ return -EINVAL;
-+
-+ ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to set mac rx frame length\n");
-+ return ret;
-+ }
-+
-+ return usbnet_change_mtu(netdev, new_mtu);
-+}
-+
-+/* Enable or disable Rx checksum offload engine */
-+static int smsc75xx_set_features(struct net_device *netdev,
-+ netdev_features_t features)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ unsigned long flags;
-+ int ret;
-+
-+ spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
-+
-+ if (features & NETIF_F_RXCSUM)
-+ pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
-+ else
-+ pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
-+
-+ spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
-+ /* it's racing here! */
-+
-+ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "Error writing RFE_CTL\n");
-+
-+ return ret;
-+}
-+
-+static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
-+{
-+ int timeout = 0;
-+
-+ do {
-+ u32 buf;
-+ int ret;
-+
-+ ret = __smsc75xx_read_reg(dev, PMT_CTL, &buf, in_pm);
-+
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ if (buf & PMT_CTL_DEV_RDY)
-+ return 0;
-+
-+ msleep(10);
-+ timeout++;
-+ } while (timeout < 100);
-+
-+ netdev_warn(dev->net, "timeout waiting for device ready\n");
-+ return -EIO;
-+}
-+
-+static int smsc75xx_reset(struct usbnet *dev)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 buf;
-+ int ret = 0, timeout;
-+
-+ netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset\n");
-+
-+ ret = smsc75xx_wait_ready(dev, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "device not ready in smsc75xx_reset\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= HW_CFG_LRST;
-+
-+ ret = smsc75xx_write_reg(dev, HW_CFG, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ timeout = 0;
-+ do {
-+ msleep(10);
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+ timeout++;
-+ } while ((buf & HW_CFG_LRST) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout on completion of Lite Reset\n");
-+ return -EIO;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY\n");
-+
-+ ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= PMT_CTL_PHY_RST;
-+
-+ ret = smsc75xx_write_reg(dev, PMT_CTL, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ timeout = 0;
-+ do {
-+ msleep(10);
-+ ret = smsc75xx_read_reg(dev, PMT_CTL, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret);
-+ return ret;
-+ }
-+ timeout++;
-+ } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
-+ return -EIO;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "PHY reset complete\n");
-+
-+ ret = smsc75xx_set_mac_address(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to set mac address\n");
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n",
-+ dev->net->dev_addr);
-+
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
-+ buf);
-+
-+ buf |= HW_CFG_BIR;
-+
-+ ret = smsc75xx_write_reg(dev, HW_CFG, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after writing HW_CFG_BIR: 0x%08x\n",
-+ buf);
-+
-+ if (!turbo_mode) {
-+ buf = 0;
-+ dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
-+ } else if (dev->udev->speed == USB_SPEED_HIGH) {
-+ buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
-+ dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
-+ } else {
-+ buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
-+ dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
-+ (ulong)dev->rx_urb_size);
-+
-+ ret = smsc75xx_write_reg(dev, BURST_CAP, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, BURST_CAP, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from BURST_CAP after writing: 0x%08x\n", buf);
-+
-+ ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from BULK_IN_DLY after writing: 0x%08x\n", buf);
-+
-+ if (turbo_mode) {
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
-+
-+ buf |= (HW_CFG_MEF | HW_CFG_BCE);
-+
-+ ret = smsc75xx_write_reg(dev, HW_CFG, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, HW_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf);
-+ }
-+
-+ /* set FIFO sizes */
-+ buf = (MAX_RX_FIFO_SIZE - 512) / 512;
-+ ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FCT_RX_FIFO_END: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x\n", buf);
-+
-+ buf = (MAX_TX_FIFO_SIZE - 512) / 512;
-+ ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FCT_TX_FIFO_END: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x\n", buf);
-+
-+ ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, ID_REV, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", buf);
-+
-+ ret = smsc75xx_read_reg(dev, E2P_CMD, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read E2P_CMD: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* only set default GPIO/LED settings if no EEPROM is detected */
-+ if (!(buf & E2P_CMD_LOADED)) {
-+ ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read LED_GPIO_CFG: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL);
-+ buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL;
-+
-+ ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, FLOW, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, FCT_FLOW, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FCT_FLOW: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Don't need rfe_ctl_lock during initialisation */
-+ ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF;
-+
-+ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write RFE_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x\n",
-+ pdata->rfe_ctl);
-+
-+ /* Enable or disable checksum offload engines */
-+ smsc75xx_set_features(dev->net, dev->net->features);
-+
-+ smsc75xx_set_multicast(dev->net);
-+
-+ ret = smsc75xx_phy_initialize(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to initialize PHY: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* enable PHY interrupts */
-+ buf |= INT_ENP_PHY_INT;
-+
-+ ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* allow mac to detect speed and duplex from phy */
-+ ret = smsc75xx_read_reg(dev, MAC_CR, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= (MAC_CR_ADD | MAC_CR_ASD);
-+ ret = smsc75xx_write_reg(dev, MAC_CR, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret);
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, MAC_TX, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read MAC_TX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= MAC_TX_TXEN;
-+
-+ ret = smsc75xx_write_reg(dev, MAC_TX, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_TX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x\n", buf);
-+
-+ ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read FCT_TX_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= FCT_TX_CTL_EN;
-+
-+ ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FCT_TX_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf);
-+
-+ ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to set max rx frame length\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_read_reg(dev, MAC_RX, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= MAC_RX_RXEN;
-+
-+ ret = smsc75xx_write_reg(dev, MAC_RX, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x\n", buf);
-+
-+ ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read FCT_RX_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ buf |= FCT_RX_CTL_EN;
-+
-+ ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write FCT_RX_CTL: %d\n", ret);
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x\n", buf);
-+
-+ netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0\n");
-+ return 0;
-+}
-+
-+static const struct net_device_ops smsc75xx_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = smsc75xx_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = smsc75xx_ioctl,
-+ .ndo_set_rx_mode = smsc75xx_set_multicast,
-+ .ndo_set_features = smsc75xx_set_features,
-+};
-+
-+static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct smsc75xx_priv *pdata = NULL;
-+ int ret;
-+
-+ printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
-+
-+ ret = usbnet_get_endpoints(dev, intf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
-+ return ret;
-+ }
-+
-+ dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv),
-+ GFP_KERNEL);
-+
-+ pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ if (!pdata)
-+ return -ENOMEM;
-+
-+ pdata->dev = dev;
-+
-+ spin_lock_init(&pdata->rfe_ctl_lock);
-+ mutex_init(&pdata->dataport_mutex);
-+
-+ INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
-+
-+ if (DEFAULT_TX_CSUM_ENABLE)
-+ dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-+
-+ if (DEFAULT_RX_CSUM_ENABLE)
-+ dev->net->features |= NETIF_F_RXCSUM;
-+
-+ dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+
-+ ret = smsc75xx_wait_ready(dev, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "device not ready in smsc75xx_bind\n");
-+ return ret;
-+ }
-+
-+ smsc75xx_init_mac_address(dev);
-+
-+ /* Init all registers */
-+ ret = smsc75xx_reset(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
-+ return ret;
-+ }
-+
-+ dev->net->netdev_ops = &smsc75xx_netdev_ops;
-+ dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
-+ dev->net->flags |= IFF_MULTICAST;
-+ dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
-+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-+ return 0;
-+}
-+
-+static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ if (pdata) {
-+ netif_dbg(dev, ifdown, dev->net, "free pdata\n");
-+ kfree(pdata);
-+ pdata = NULL;
-+ dev->data[0] = 0;
-+ }
-+}
-+
-+static u16 smsc_crc(const u8 *buffer, size_t len)
-+{
-+ return bitrev16(crc16(0xFFFF, buffer, len));
-+}
-+
-+static int smsc75xx_write_wuff(struct usbnet *dev, int filter, u32 wuf_cfg,
-+ u32 wuf_mask1)
-+{
-+ int cfg_base = WUF_CFGX + filter * 4;
-+ int mask_base = WUF_MASKX + filter * 16;
-+ int ret;
-+
-+ ret = smsc75xx_write_reg(dev, cfg_base, wuf_cfg);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_CFGX\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, mask_base, wuf_mask1);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, mask_base + 4, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, mask_base + 8, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_write_reg(dev, mask_base + 12, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_MASKX\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_enter_suspend0(struct usbnet *dev)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST));
-+ val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND0;
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_enter_suspend1(struct usbnet *dev)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
-+ val |= PMT_CTL_SUS_MODE_1;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ /* clear wol status, enable energy detection */
-+ val &= ~PMT_CTL_WUPS;
-+ val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND1;
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_enter_suspend2(struct usbnet *dev)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
-+ val |= PMT_CTL_SUS_MODE_2;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND2;
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_enter_suspend3(struct usbnet *dev)
-+{
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc75xx_read_reg_nopm(dev, FCT_RX_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading FCT_RX_CTL\n");
-+ return ret;
-+ }
-+
-+ if (val & FCT_RX_CTL_RXUSED) {
-+ netdev_dbg(dev->net, "rx fifo not empty in autosuspend\n");
-+ return -EBUSY;
-+ }
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST);
-+ val |= PMT_CTL_SUS_MODE_3 | PMT_CTL_RES_CLR_WKP_EN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ /* clear wol status */
-+ val &= ~PMT_CTL_WUPS;
-+ val |= PMT_CTL_WUPS_WOL;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND3;
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
-+{
-+ struct mii_if_info *mii = &dev->mii;
-+ int ret;
-+
-+ netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n");
-+
-+ /* read to clear */
-+ ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PHY_INT_SRC\n");
-+ return ret;
-+ }
-+
-+ /* enable interrupt source */
-+ ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PHY_INT_MASK\n");
-+ return ret;
-+ }
-+
-+ ret |= mask;
-+
-+ smsc75xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret);
-+
-+ return 0;
-+}
-+
-+static int smsc75xx_link_ok_nopm(struct usbnet *dev)
-+{
-+ struct mii_if_info *mii = &dev->mii;
-+ int ret;
-+
-+ /* first, a dummy read, needed to latch some MII phys */
-+ ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_BMSR\n");
-+ return ret;
-+ }
-+
-+ ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_BMSR\n");
-+ return ret;
-+ }
-+
-+ return !!(ret & BMSR_LSTATUS);
-+}
-+
-+static int smsc75xx_autosuspend(struct usbnet *dev, u32 link_up)
-+{
-+ int ret;
-+
-+ if (!netif_running(dev->net)) {
-+ /* interface is ifconfig down so fully power down hw */
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
-+ return smsc75xx_enter_suspend2(dev);
-+ }
-+
-+ if (!link_up) {
-+ /* link is down so enter EDPD mode */
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
-+
-+ /* enable PHY wakeup events for if cable is attached */
-+ ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
-+ PHY_INT_MASK_ANEG_COMP);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ return ret;
-+ }
-+
-+ netdev_info(dev->net, "entering SUSPEND1 mode\n");
-+ return smsc75xx_enter_suspend1(dev);
-+ }
-+
-+ /* enable PHY wakeup events so we remote wakeup if cable is pulled */
-+ ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
-+ PHY_INT_MASK_LINK_DOWN);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ return ret;
-+ }
-+
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
-+ return smsc75xx_enter_suspend3(dev);
-+}
-+
-+static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u32 val, link_up;
-+ int ret;
-+
-+ ret = usbnet_suspend(intf, message);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "usbnet_suspend error\n");
-+ return ret;
-+ }
-+
-+ if (pdata->suspend_flags) {
-+ netdev_warn(dev->net, "error during last resume\n");
-+ pdata->suspend_flags = 0;
-+ }
-+
-+ /* determine if link is up using only _nopm functions */
-+ link_up = smsc75xx_link_ok_nopm(dev);
-+
-+ if (message.event == PM_EVENT_AUTO_SUSPEND) {
-+ ret = smsc75xx_autosuspend(dev, link_up);
-+ goto done;
-+ }
-+
-+ /* if we get this far we're not autosuspending */
-+ /* if no wol options set, or if link is down and we're not waking on
-+ * PHY activity, enter lowest power SUSPEND2 mode
-+ */
-+ if (!(pdata->wolopts & SUPPORTED_WAKE) ||
-+ !(link_up || (pdata->wolopts & WAKE_PHY))) {
-+ netdev_info(dev->net, "entering SUSPEND2 mode\n");
-+
-+ /* disable energy detect (link up) & wake up events */
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val &= ~(WUCSR_MPEN | WUCSR_WUEN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ goto done;
-+ }
-+
-+ val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ goto done;
-+ }
-+
-+ ret = smsc75xx_enter_suspend2(dev);
-+ goto done;
-+ }
-+
-+ if (pdata->wolopts & WAKE_PHY) {
-+ ret = smsc75xx_enable_phy_wakeup_interrupts(dev,
-+ (PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN));
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ goto done;
-+ }
-+
-+ /* if link is down then configure EDPD and enter SUSPEND1,
-+ * otherwise enter SUSPEND0 below
-+ */
-+ if (!link_up) {
-+ struct mii_if_info *mii = &dev->mii;
-+ netdev_info(dev->net, "entering SUSPEND1 mode\n");
-+
-+ /* enable energy detect power-down mode */
-+ ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id,
-+ PHY_MODE_CTRL_STS);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n");
-+ goto done;
-+ }
-+
-+ ret |= MODE_CTRL_STS_EDPWRDOWN;
-+
-+ smsc75xx_mdio_write_nopm(dev->net, mii->phy_id,
-+ PHY_MODE_CTRL_STS, ret);
-+
-+ /* enter SUSPEND1 mode */
-+ ret = smsc75xx_enter_suspend1(dev);
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & (WAKE_MCAST | WAKE_ARP)) {
-+ int i, filter = 0;
-+
-+ /* disable all filters */
-+ for (i = 0; i < WUF_NUM; i++) {
-+ ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUF_CFGX\n");
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & WAKE_MCAST) {
-+ const u8 mcast[] = {0x01, 0x00, 0x5E};
-+ netdev_info(dev->net, "enabling multicast detection\n");
-+
-+ val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST
-+ | smsc_crc(mcast, 3);
-+ ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing wakeup filter\n");
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & WAKE_ARP) {
-+ const u8 arp[] = {0x08, 0x06};
-+ netdev_info(dev->net, "enabling ARP detection\n");
-+
-+ val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16)
-+ | smsc_crc(arp, 2);
-+ ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing wakeup filter\n");
-+ goto done;
-+ }
-+ }
-+
-+ /* clear any pending pattern match packet status */
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val |= WUCSR_WUFR;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+
-+ netdev_info(dev->net, "enabling packet match detection\n");
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val |= WUCSR_WUEN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+ } else {
-+ netdev_info(dev->net, "disabling packet match detection\n");
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val &= ~WUCSR_WUEN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+ }
-+
-+ /* disable magic, bcast & unicast wakeup sources */
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+
-+ if (pdata->wolopts & WAKE_PHY) {
-+ netdev_info(dev->net, "enabling PHY wakeup\n");
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ goto done;
-+ }
-+
-+ /* clear wol status, enable energy detection */
-+ val &= ~PMT_CTL_WUPS;
-+ val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & WAKE_MAGIC) {
-+ netdev_info(dev->net, "enabling magic packet wakeup\n");
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ /* clear any pending magic packet status */
-+ val |= WUCSR_MPR | WUCSR_MPEN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & WAKE_BCAST) {
-+ netdev_info(dev->net, "enabling broadcast detection\n");
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val |= WUCSR_BCAST_FR | WUCSR_BCST_EN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & WAKE_UCAST) {
-+ netdev_info(dev->net, "enabling unicast detection\n");
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ goto done;
-+ }
-+
-+ val |= WUCSR_WUFR | WUCSR_PFDA_EN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ goto done;
-+ }
-+ }
-+
-+ /* enable receiver to enable frame reception */
-+ ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret);
-+ goto done;
-+ }
-+
-+ val |= MAC_RX_RXEN;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret);
-+ goto done;
-+ }
-+
-+ /* some wol options are enabled, so enter SUSPEND0 */
-+ netdev_info(dev->net, "entering SUSPEND0 mode\n");
-+ ret = smsc75xx_enter_suspend0(dev);
-+
-+done:
-+ /*
-+ * TODO: resume() might need to handle the suspend failure
-+ * in system sleep
-+ */
-+ if (ret && PMSG_IS_AUTO(message))
-+ usbnet_resume(intf);
-+ return ret;
-+}
-+
-+static int smsc75xx_resume(struct usb_interface *intf)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-+ u8 suspend_flags = pdata->suspend_flags;
-+ int ret;
-+ u32 val;
-+
-+ netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
-+
-+ /* do this first to ensure it's cleared even in error case */
-+ pdata->suspend_flags = 0;
-+
-+ if (suspend_flags & SUSPEND_ALLMODES) {
-+ /* Disable wakeup sources */
-+ ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading WUCSR\n");
-+ return ret;
-+ }
-+
-+ val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN
-+ | WUCSR_BCST_EN);
-+
-+ ret = smsc75xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing WUCSR\n");
-+ return ret;
-+ }
-+
-+ /* clear wake-up status */
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val &= ~PMT_CTL_WOL_EN;
-+ val |= PMT_CTL_WUPS;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+ }
-+
-+ if (suspend_flags & SUSPEND_SUSPEND2) {
-+ netdev_info(dev->net, "resuming from SUSPEND2\n");
-+
-+ ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading PMT_CTL\n");
-+ return ret;
-+ }
-+
-+ val |= PMT_CTL_PHY_PWRUP;
-+
-+ ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing PMT_CTL\n");
-+ return ret;
-+ }
-+ }
-+
-+ ret = smsc75xx_wait_ready(dev, 1);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "device not ready in smsc75xx_resume\n");
-+ return ret;
-+ }
-+
-+ return usbnet_resume(intf);
-+}
-+
-+static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
-+ u32 rx_cmd_a, u32 rx_cmd_b)
-+{
-+ if (!(dev->net->features & NETIF_F_RXCSUM) ||
-+ unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
-+ skb->ip_summed = CHECKSUM_NONE;
-+ } else {
-+ skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT));
-+ skb->ip_summed = CHECKSUM_COMPLETE;
-+ }
-+}
-+
-+static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ while (skb->len > 0) {
-+ u32 rx_cmd_a, rx_cmd_b, align_count, size;
-+ struct sk_buff *ax_skb;
-+ unsigned char *packet;
-+
-+ memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a));
-+ le32_to_cpus(&rx_cmd_a);
-+ skb_pull(skb, 4);
-+
-+ memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b));
-+ le32_to_cpus(&rx_cmd_b);
-+ skb_pull(skb, 4 + RXW_PADDING);
-+
-+ packet = skb->data;
-+
-+ /* get the packet length */
-+ size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING;
-+ align_count = (4 - ((size + RXW_PADDING) % 4)) % 4;
-+
-+ if (unlikely(rx_cmd_a & RX_CMD_A_RED)) {
-+ netif_dbg(dev, rx_err, dev->net,
-+ "Error rx_cmd_a=0x%08x\n", rx_cmd_a);
-+ dev->net->stats.rx_errors++;
-+ dev->net->stats.rx_dropped++;
-+
-+ if (rx_cmd_a & RX_CMD_A_FCS)
-+ dev->net->stats.rx_crc_errors++;
-+ else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))
-+ dev->net->stats.rx_frame_errors++;
-+ } else {
-+ /* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */
-+ if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) {
-+ netif_dbg(dev, rx_err, dev->net,
-+ "size err rx_cmd_a=0x%08x\n",
-+ rx_cmd_a);
-+ return 0;
-+ }
-+
-+ /* last frame in this batch */
-+ if (skb->len == size) {
-+ smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a,
-+ rx_cmd_b);
-+
-+ skb_trim(skb, skb->len - 4); /* remove fcs */
-+ skb->truesize = size + sizeof(struct sk_buff);
-+
-+ return 1;
-+ }
-+
-+ ax_skb = skb_clone(skb, GFP_ATOMIC);
-+ if (unlikely(!ax_skb)) {
-+ netdev_warn(dev->net, "Error allocating skb\n");
-+ return 0;
-+ }
-+
-+ ax_skb->len = size;
-+ ax_skb->data = packet;
-+ skb_set_tail_pointer(ax_skb, size);
-+
-+ smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a,
-+ rx_cmd_b);
-+
-+ skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
-+ ax_skb->truesize = size + sizeof(struct sk_buff);
-+
-+ usbnet_skb_return(dev, ax_skb);
-+ }
-+
-+ skb_pull(skb, size);
-+
-+ /* padding bytes before the next frame starts */
-+ if (skb->len)
-+ skb_pull(skb, align_count);
-+ }
-+
-+ if (unlikely(skb->len < 0)) {
-+ netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
-+ struct sk_buff *skb, gfp_t flags)
-+{
-+ u32 tx_cmd_a, tx_cmd_b;
-+
-+ if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
-+ struct sk_buff *skb2 =
-+ skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS;
-+
-+ if (skb->ip_summed == CHECKSUM_PARTIAL)
-+ tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE;
-+
-+ if (skb_is_gso(skb)) {
-+ u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN);
-+ tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS;
-+
-+ tx_cmd_a |= TX_CMD_A_LSO;
-+ } else {
-+ tx_cmd_b = 0;
-+ }
-+
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&tx_cmd_b);
-+ memcpy(skb->data, &tx_cmd_b, 4);
-+
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&tx_cmd_a);
-+ memcpy(skb->data, &tx_cmd_a, 4);
-+
-+ return skb;
-+}
-+
-+static int smsc75xx_manage_power(struct usbnet *dev, int on)
-+{
-+ dev->intf->needs_remote_wakeup = on;
-+ return 0;
-+}
-+
-+static const struct driver_info smsc75xx_info = {
-+ .description = "smsc75xx USB 2.0 Gigabit Ethernet",
-+ .bind = smsc75xx_bind,
-+ .unbind = smsc75xx_unbind,
-+ .link_reset = smsc75xx_link_reset,
-+ .reset = smsc75xx_reset,
-+ .rx_fixup = smsc75xx_rx_fixup,
-+ .tx_fixup = smsc75xx_tx_fixup,
-+ .status = smsc75xx_status,
-+ .manage_power = smsc75xx_manage_power,
-+ .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ /* SMSC7500 USB Gigabit Ethernet Device */
-+ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500),
-+ .driver_info = (unsigned long) &smsc75xx_info,
-+ },
-+ {
-+ /* SMSC7500 USB Gigabit Ethernet Device */
-+ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505),
-+ .driver_info = (unsigned long) &smsc75xx_info,
-+ },
-+ { }, /* END */
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver smsc75xx_driver = {
-+ .name = SMSC_CHIPNAME,
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .suspend = smsc75xx_suspend,
-+ .resume = smsc75xx_resume,
-+ .reset_resume = smsc75xx_resume,
-+ .disconnect = usbnet_disconnect,
-+ .disable_hub_initiated_lpm = 1,
-+ .supports_autosuspend = 1,
-+};
-+
-+module_usb_driver(smsc75xx_driver);
-+
-+MODULE_AUTHOR("Nancy Lin");
-+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
-+MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/smsc75xx.h backports-4.2.6-1/drivers/net/usb/smsc75xx.h
---- backports-4.2.6-1.org/drivers/net/usb/smsc75xx.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/smsc75xx.h 2016-06-28 14:35:18.008640551 +0200
-@@ -0,0 +1,421 @@
-+ /***************************************************************************
-+ *
-+ * Copyright (C) 2007-2010 SMSC
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ *****************************************************************************/
-+
-+#ifndef _SMSC75XX_H
-+#define _SMSC75XX_H
-+
-+/* Tx command words */
-+#define TX_CMD_A_LSO (0x08000000)
-+#define TX_CMD_A_IPE (0x04000000)
-+#define TX_CMD_A_TPE (0x02000000)
-+#define TX_CMD_A_IVTG (0x01000000)
-+#define TX_CMD_A_RVTG (0x00800000)
-+#define TX_CMD_A_FCS (0x00400000)
-+#define TX_CMD_A_LEN (0x000FFFFF)
-+
-+#define TX_CMD_B_MSS (0x3FFF0000)
-+#define TX_CMD_B_MSS_SHIFT (16)
-+#define TX_MSS_MIN ((u16)8)
-+#define TX_CMD_B_VTAG (0x0000FFFF)
-+
-+/* Rx command words */
-+#define RX_CMD_A_ICE (0x80000000)
-+#define RX_CMD_A_TCE (0x40000000)
-+#define RX_CMD_A_IPV (0x20000000)
-+#define RX_CMD_A_PID (0x18000000)
-+#define RX_CMD_A_PID_NIP (0x00000000)
-+#define RX_CMD_A_PID_TCP (0x08000000)
-+#define RX_CMD_A_PID_UDP (0x10000000)
-+#define RX_CMD_A_PID_PP (0x18000000)
-+#define RX_CMD_A_PFF (0x04000000)
-+#define RX_CMD_A_BAM (0x02000000)
-+#define RX_CMD_A_MAM (0x01000000)
-+#define RX_CMD_A_FVTG (0x00800000)
-+#define RX_CMD_A_RED (0x00400000)
-+#define RX_CMD_A_RWT (0x00200000)
-+#define RX_CMD_A_RUNT (0x00100000)
-+#define RX_CMD_A_LONG (0x00080000)
-+#define RX_CMD_A_RXE (0x00040000)
-+#define RX_CMD_A_DRB (0x00020000)
-+#define RX_CMD_A_FCS (0x00010000)
-+#define RX_CMD_A_UAM (0x00008000)
-+#define RX_CMD_A_LCSM (0x00004000)
-+#define RX_CMD_A_LEN (0x00003FFF)
-+
-+#define RX_CMD_B_CSUM (0xFFFF0000)
-+#define RX_CMD_B_CSUM_SHIFT (16)
-+#define RX_CMD_B_VTAG (0x0000FFFF)
-+
-+/* SCSRs */
-+#define ID_REV (0x0000)
-+
-+#define FPGA_REV (0x0004)
-+
-+#define BOND_CTL (0x0008)
-+
-+#define INT_STS (0x000C)
-+#define INT_STS_RDFO_INT (0x00400000)
-+#define INT_STS_TXE_INT (0x00200000)
-+#define INT_STS_MACRTO_INT (0x00100000)
-+#define INT_STS_TX_DIS_INT (0x00080000)
-+#define INT_STS_RX_DIS_INT (0x00040000)
-+#define INT_STS_PHY_INT_ (0x00020000)
-+#define INT_STS_MAC_ERR_INT (0x00008000)
-+#define INT_STS_TDFU (0x00004000)
-+#define INT_STS_TDFO (0x00002000)
-+#define INT_STS_GPIOS (0x00000FFF)
-+#define INT_STS_CLEAR_ALL (0xFFFFFFFF)
-+
-+#define HW_CFG (0x0010)
-+#define HW_CFG_SMDET_STS (0x00008000)
-+#define HW_CFG_SMDET_EN (0x00004000)
-+#define HW_CFG_EEM (0x00002000)
-+#define HW_CFG_RST_PROTECT (0x00001000)
-+#define HW_CFG_PORT_SWAP (0x00000800)
-+#define HW_CFG_PHY_BOOST (0x00000600)
-+#define HW_CFG_PHY_BOOST_NORMAL (0x00000000)
-+#define HW_CFG_PHY_BOOST_4 (0x00002000)
-+#define HW_CFG_PHY_BOOST_8 (0x00004000)
-+#define HW_CFG_PHY_BOOST_12 (0x00006000)
-+#define HW_CFG_LEDB (0x00000100)
-+#define HW_CFG_BIR (0x00000080)
-+#define HW_CFG_SBP (0x00000040)
-+#define HW_CFG_IME (0x00000020)
-+#define HW_CFG_MEF (0x00000010)
-+#define HW_CFG_ETC (0x00000008)
-+#define HW_CFG_BCE (0x00000004)
-+#define HW_CFG_LRST (0x00000002)
-+#define HW_CFG_SRST (0x00000001)
-+
-+#define PMT_CTL (0x0014)
-+#define PMT_CTL_PHY_PWRUP (0x00000400)
-+#define PMT_CTL_RES_CLR_WKP_EN (0x00000100)
-+#define PMT_CTL_DEV_RDY (0x00000080)
-+#define PMT_CTL_SUS_MODE (0x00000060)
-+#define PMT_CTL_SUS_MODE_0 (0x00000000)
-+#define PMT_CTL_SUS_MODE_1 (0x00000020)
-+#define PMT_CTL_SUS_MODE_2 (0x00000040)
-+#define PMT_CTL_SUS_MODE_3 (0x00000060)
-+#define PMT_CTL_PHY_RST (0x00000010)
-+#define PMT_CTL_WOL_EN (0x00000008)
-+#define PMT_CTL_ED_EN (0x00000004)
-+#define PMT_CTL_WUPS (0x00000003)
-+#define PMT_CTL_WUPS_NO (0x00000000)
-+#define PMT_CTL_WUPS_ED (0x00000001)
-+#define PMT_CTL_WUPS_WOL (0x00000002)
-+#define PMT_CTL_WUPS_MULTI (0x00000003)
-+
-+#define LED_GPIO_CFG (0x0018)
-+#define LED_GPIO_CFG_LED2_FUN_SEL (0x80000000)
-+#define LED_GPIO_CFG_LED10_FUN_SEL (0x40000000)
-+#define LED_GPIO_CFG_LEDGPIO_EN (0x0000F000)
-+#define LED_GPIO_CFG_LEDGPIO_EN_0 (0x00001000)
-+#define LED_GPIO_CFG_LEDGPIO_EN_1 (0x00002000)
-+#define LED_GPIO_CFG_LEDGPIO_EN_2 (0x00004000)
-+#define LED_GPIO_CFG_LEDGPIO_EN_3 (0x00008000)
-+#define LED_GPIO_CFG_GPBUF (0x00000F00)
-+#define LED_GPIO_CFG_GPBUF_0 (0x00000100)
-+#define LED_GPIO_CFG_GPBUF_1 (0x00000200)
-+#define LED_GPIO_CFG_GPBUF_2 (0x00000400)
-+#define LED_GPIO_CFG_GPBUF_3 (0x00000800)
-+#define LED_GPIO_CFG_GPDIR (0x000000F0)
-+#define LED_GPIO_CFG_GPDIR_0 (0x00000010)
-+#define LED_GPIO_CFG_GPDIR_1 (0x00000020)
-+#define LED_GPIO_CFG_GPDIR_2 (0x00000040)
-+#define LED_GPIO_CFG_GPDIR_3 (0x00000080)
-+#define LED_GPIO_CFG_GPDATA (0x0000000F)
-+#define LED_GPIO_CFG_GPDATA_0 (0x00000001)
-+#define LED_GPIO_CFG_GPDATA_1 (0x00000002)
-+#define LED_GPIO_CFG_GPDATA_2 (0x00000004)
-+#define LED_GPIO_CFG_GPDATA_3 (0x00000008)
-+
-+#define GPIO_CFG (0x001C)
-+#define GPIO_CFG_SHIFT (24)
-+#define GPIO_CFG_GPEN (0xFF000000)
-+#define GPIO_CFG_GPBUF (0x00FF0000)
-+#define GPIO_CFG_GPDIR (0x0000FF00)
-+#define GPIO_CFG_GPDATA (0x000000FF)
-+
-+#define GPIO_WAKE (0x0020)
-+#define GPIO_WAKE_PHY_LINKUP_EN (0x80000000)
-+#define GPIO_WAKE_POL (0x0FFF0000)
-+#define GPIO_WAKE_POL_SHIFT (16)
-+#define GPIO_WAKE_WK (0x00000FFF)
-+
-+#define DP_SEL (0x0024)
-+#define DP_SEL_DPRDY (0x80000000)
-+#define DP_SEL_RSEL (0x0000000F)
-+#define DP_SEL_URX (0x00000000)
-+#define DP_SEL_VHF (0x00000001)
-+#define DP_SEL_VHF_HASH_LEN (16)
-+#define DP_SEL_VHF_VLAN_LEN (128)
-+#define DP_SEL_LSO_HEAD (0x00000002)
-+#define DP_SEL_FCT_RX (0x00000003)
-+#define DP_SEL_FCT_TX (0x00000004)
-+#define DP_SEL_DESCRIPTOR (0x00000005)
-+#define DP_SEL_WOL (0x00000006)
-+
-+#define DP_CMD (0x0028)
-+#define DP_CMD_WRITE (0x01)
-+#define DP_CMD_READ (0x00)
-+
-+#define DP_ADDR (0x002C)
-+
-+#define DP_DATA (0x0030)
-+
-+#define BURST_CAP (0x0034)
-+#define BURST_CAP_MASK (0x0000000F)
-+
-+#define INT_EP_CTL (0x0038)
-+#define INT_EP_CTL_INTEP_ON (0x80000000)
-+#define INT_EP_CTL_RDFO_EN (0x00400000)
-+#define INT_EP_CTL_TXE_EN (0x00200000)
-+#define INT_EP_CTL_MACROTO_EN (0x00100000)
-+#define INT_EP_CTL_TX_DIS_EN (0x00080000)
-+#define INT_EP_CTL_RX_DIS_EN (0x00040000)
-+#define INT_EP_CTL_PHY_EN_ (0x00020000)
-+#define INT_EP_CTL_MAC_ERR_EN (0x00008000)
-+#define INT_EP_CTL_TDFU_EN (0x00004000)
-+#define INT_EP_CTL_TDFO_EN (0x00002000)
-+#define INT_EP_CTL_RX_FIFO_EN (0x00001000)
-+#define INT_EP_CTL_GPIOX_EN (0x00000FFF)
-+
-+#define BULK_IN_DLY (0x003C)
-+#define BULK_IN_DLY_MASK (0xFFFF)
-+
-+#define E2P_CMD (0x0040)
-+#define E2P_CMD_BUSY (0x80000000)
-+#define E2P_CMD_MASK (0x70000000)
-+#define E2P_CMD_READ (0x00000000)
-+#define E2P_CMD_EWDS (0x10000000)
-+#define E2P_CMD_EWEN (0x20000000)
-+#define E2P_CMD_WRITE (0x30000000)
-+#define E2P_CMD_WRAL (0x40000000)
-+#define E2P_CMD_ERASE (0x50000000)
-+#define E2P_CMD_ERAL (0x60000000)
-+#define E2P_CMD_RELOAD (0x70000000)
-+#define E2P_CMD_TIMEOUT (0x00000400)
-+#define E2P_CMD_LOADED (0x00000200)
-+#define E2P_CMD_ADDR (0x000001FF)
-+
-+#define MAX_EEPROM_SIZE (512)
-+
-+#define E2P_DATA (0x0044)
-+#define E2P_DATA_MASK_ (0x000000FF)
-+
-+#define RFE_CTL (0x0060)
-+#define RFE_CTL_TCPUDP_CKM (0x00001000)
-+#define RFE_CTL_IP_CKM (0x00000800)
-+#define RFE_CTL_AB (0x00000400)
-+#define RFE_CTL_AM (0x00000200)
-+#define RFE_CTL_AU (0x00000100)
-+#define RFE_CTL_VS (0x00000080)
-+#define RFE_CTL_UF (0x00000040)
-+#define RFE_CTL_VF (0x00000020)
-+#define RFE_CTL_SPF (0x00000010)
-+#define RFE_CTL_MHF (0x00000008)
-+#define RFE_CTL_DHF (0x00000004)
-+#define RFE_CTL_DPF (0x00000002)
-+#define RFE_CTL_RST_RF (0x00000001)
-+
-+#define VLAN_TYPE (0x0064)
-+#define VLAN_TYPE_MASK (0x0000FFFF)
-+
-+#define FCT_RX_CTL (0x0090)
-+#define FCT_RX_CTL_EN (0x80000000)
-+#define FCT_RX_CTL_RST (0x40000000)
-+#define FCT_RX_CTL_SBF (0x02000000)
-+#define FCT_RX_CTL_OVERFLOW (0x01000000)
-+#define FCT_RX_CTL_FRM_DROP (0x00800000)
-+#define FCT_RX_CTL_RX_NOT_EMPTY (0x00400000)
-+#define FCT_RX_CTL_RX_EMPTY (0x00200000)
-+#define FCT_RX_CTL_RX_DISABLED (0x00100000)
-+#define FCT_RX_CTL_RXUSED (0x0000FFFF)
-+
-+#define FCT_TX_CTL (0x0094)
-+#define FCT_TX_CTL_EN (0x80000000)
-+#define FCT_TX_CTL_RST (0x40000000)
-+#define FCT_TX_CTL_TX_NOT_EMPTY (0x00400000)
-+#define FCT_TX_CTL_TX_EMPTY (0x00200000)
-+#define FCT_TX_CTL_TX_DISABLED (0x00100000)
-+#define FCT_TX_CTL_TXUSED (0x0000FFFF)
-+
-+#define FCT_RX_FIFO_END (0x0098)
-+#define FCT_RX_FIFO_END_MASK (0x0000007F)
-+
-+#define FCT_TX_FIFO_END (0x009C)
-+#define FCT_TX_FIFO_END_MASK (0x0000003F)
-+
-+#define FCT_FLOW (0x00A0)
-+#define FCT_FLOW_THRESHOLD_OFF (0x00007F00)
-+#define FCT_FLOW_THRESHOLD_OFF_SHIFT (8)
-+#define FCT_FLOW_THRESHOLD_ON (0x0000007F)
-+
-+/* MAC CSRs */
-+#define MAC_CR (0x100)
-+#define MAC_CR_ADP (0x00002000)
-+#define MAC_CR_ADD (0x00001000)
-+#define MAC_CR_ASD (0x00000800)
-+#define MAC_CR_INT_LOOP (0x00000400)
-+#define MAC_CR_BOLMT (0x000000C0)
-+#define MAC_CR_FDPX (0x00000008)
-+#define MAC_CR_CFG (0x00000006)
-+#define MAC_CR_CFG_10 (0x00000000)
-+#define MAC_CR_CFG_100 (0x00000002)
-+#define MAC_CR_CFG_1000 (0x00000004)
-+#define MAC_CR_RST (0x00000001)
-+
-+#define MAC_RX (0x104)
-+#define MAC_RX_MAX_SIZE (0x3FFF0000)
-+#define MAC_RX_MAX_SIZE_SHIFT (16)
-+#define MAC_RX_FCS_STRIP (0x00000010)
-+#define MAC_RX_FSE (0x00000004)
-+#define MAC_RX_RXD (0x00000002)
-+#define MAC_RX_RXEN (0x00000001)
-+
-+#define MAC_TX (0x108)
-+#define MAC_TX_BFCS (0x00000004)
-+#define MAC_TX_TXD (0x00000002)
-+#define MAC_TX_TXEN (0x00000001)
-+
-+#define FLOW (0x10C)
-+#define FLOW_FORCE_FC (0x80000000)
-+#define FLOW_TX_FCEN (0x40000000)
-+#define FLOW_RX_FCEN (0x20000000)
-+#define FLOW_FPF (0x10000000)
-+#define FLOW_PAUSE_TIME (0x0000FFFF)
-+
-+#define RAND_SEED (0x110)
-+#define RAND_SEED_MASK (0x0000FFFF)
-+
-+#define ERR_STS (0x114)
-+#define ERR_STS_FCS_ERR (0x00000100)
-+#define ERR_STS_LFRM_ERR (0x00000080)
-+#define ERR_STS_RUNT_ERR (0x00000040)
-+#define ERR_STS_COLLISION_ERR (0x00000010)
-+#define ERR_STS_ALIGN_ERR (0x00000008)
-+#define ERR_STS_URUN_ERR (0x00000004)
-+
-+#define RX_ADDRH (0x118)
-+#define RX_ADDRH_MASK (0x0000FFFF)
-+
-+#define RX_ADDRL (0x11C)
-+
-+#define MII_ACCESS (0x120)
-+#define MII_ACCESS_PHY_ADDR (0x0000F800)
-+#define MII_ACCESS_PHY_ADDR_SHIFT (11)
-+#define MII_ACCESS_REG_ADDR (0x000007C0)
-+#define MII_ACCESS_REG_ADDR_SHIFT (6)
-+#define MII_ACCESS_READ (0x00000000)
-+#define MII_ACCESS_WRITE (0x00000002)
-+#define MII_ACCESS_BUSY (0x00000001)
-+
-+#define MII_DATA (0x124)
-+#define MII_DATA_MASK (0x0000FFFF)
-+
-+#define WUCSR (0x140)
-+#define WUCSR_PFDA_FR (0x00000080)
-+#define WUCSR_WUFR (0x00000040)
-+#define WUCSR_MPR (0x00000020)
-+#define WUCSR_BCAST_FR (0x00000010)
-+#define WUCSR_PFDA_EN (0x00000008)
-+#define WUCSR_WUEN (0x00000004)
-+#define WUCSR_MPEN (0x00000002)
-+#define WUCSR_BCST_EN (0x00000001)
-+
-+#define WUF_CFGX (0x144)
-+#define WUF_CFGX_EN (0x80000000)
-+#define WUF_CFGX_ATYPE (0x03000000)
-+#define WUF_CFGX_ATYPE_UNICAST (0x00000000)
-+#define WUF_CFGX_ATYPE_MULTICAST (0x02000000)
-+#define WUF_CFGX_ATYPE_ALL (0x03000000)
-+#define WUF_CFGX_PATTERN_OFFSET (0x007F0000)
-+#define WUF_CFGX_PATTERN_OFFSET_SHIFT (16)
-+#define WUF_CFGX_CRC16 (0x0000FFFF)
-+#define WUF_NUM (8)
-+
-+#define WUF_MASKX (0x170)
-+#define WUF_MASKX_AVALID (0x80000000)
-+#define WUF_MASKX_ATYPE (0x40000000)
-+
-+#define ADDR_FILTX (0x300)
-+#define ADDR_FILTX_FB_VALID (0x80000000)
-+#define ADDR_FILTX_FB_TYPE (0x40000000)
-+#define ADDR_FILTX_FB_ADDRHI (0x0000FFFF)
-+#define ADDR_FILTX_SB_ADDRLO (0xFFFFFFFF)
-+
-+#define WUCSR2 (0x500)
-+#define WUCSR2_NS_RCD (0x00000040)
-+#define WUCSR2_ARP_RCD (0x00000020)
-+#define WUCSR2_TCPSYN_RCD (0x00000010)
-+#define WUCSR2_NS_OFFLOAD (0x00000004)
-+#define WUCSR2_ARP_OFFLOAD (0x00000002)
-+#define WUCSR2_TCPSYN_OFFLOAD (0x00000001)
-+
-+#define WOL_FIFO_STS (0x504)
-+
-+#define IPV6_ADDRX (0x510)
-+
-+#define IPV4_ADDRX (0x590)
-+
-+
-+/* Vendor-specific PHY Definitions */
-+
-+/* Mode Control/Status Register */
-+#define PHY_MODE_CTRL_STS (17)
-+#define MODE_CTRL_STS_EDPWRDOWN ((u16)0x2000)
-+#define MODE_CTRL_STS_ENERGYON ((u16)0x0002)
-+
-+#define PHY_INT_SRC (29)
-+#define PHY_INT_SRC_ENERGY_ON ((u16)0x0080)
-+#define PHY_INT_SRC_ANEG_COMP ((u16)0x0040)
-+#define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020)
-+#define PHY_INT_SRC_LINK_DOWN ((u16)0x0010)
-+#define PHY_INT_SRC_CLEAR_ALL ((u16)0xffff)
-+
-+#define PHY_INT_MASK (30)
-+#define PHY_INT_MASK_ENERGY_ON ((u16)0x0080)
-+#define PHY_INT_MASK_ANEG_COMP ((u16)0x0040)
-+#define PHY_INT_MASK_REMOTE_FAULT ((u16)0x0020)
-+#define PHY_INT_MASK_LINK_DOWN ((u16)0x0010)
-+#define PHY_INT_MASK_DEFAULT (PHY_INT_MASK_ANEG_COMP | \
-+ PHY_INT_MASK_LINK_DOWN)
-+
-+#define PHY_SPECIAL (31)
-+#define PHY_SPECIAL_SPD ((u16)0x001C)
-+#define PHY_SPECIAL_SPD_10HALF ((u16)0x0004)
-+#define PHY_SPECIAL_SPD_10FULL ((u16)0x0014)
-+#define PHY_SPECIAL_SPD_100HALF ((u16)0x0008)
-+#define PHY_SPECIAL_SPD_100FULL ((u16)0x0018)
-+
-+/* USB Vendor Requests */
-+#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0
-+#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1
-+#define USB_VENDOR_REQUEST_GET_STATS 0xA2
-+
-+/* Interrupt Endpoint status word bitfields */
-+#define INT_ENP_RDFO_INT ((u32)BIT(22))
-+#define INT_ENP_TXE_INT ((u32)BIT(21))
-+#define INT_ENP_TX_DIS_INT ((u32)BIT(19))
-+#define INT_ENP_RX_DIS_INT ((u32)BIT(18))
-+#define INT_ENP_PHY_INT ((u32)BIT(17))
-+#define INT_ENP_MAC_ERR_INT ((u32)BIT(15))
-+#define INT_ENP_RX_FIFO_DATA_INT ((u32)BIT(12))
-+
-+#endif /* _SMSC75XX_H */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/smsc95xx.c backports-4.2.6-1/drivers/net/usb/smsc95xx.c
---- backports-4.2.6-1.org/drivers/net/usb/smsc95xx.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/smsc95xx.c 2016-06-28 14:35:18.011973884 +0200
-@@ -0,0 +1,2032 @@
-+ /***************************************************************************
-+ *
-+ * Copyright (C) 2007-2008 SMSC
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ *****************************************************************************/
-+
-+#include <linux/module.h>
-+#include <linux/kmod.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/bitrev.h>
-+#include <linux/crc16.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+#include "smsc95xx.h"
-+
-+#define SMSC_CHIPNAME "smsc95xx"
-+#define SMSC_DRIVER_VERSION "1.0.4"
-+#define HS_USB_PKT_SIZE (512)
-+#define FS_USB_PKT_SIZE (64)
-+#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
-+#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE)
-+#define DEFAULT_BULK_IN_DELAY (0x00002000)
-+#define MAX_SINGLE_PACKET_SIZE (2048)
-+#define LAN95XX_EEPROM_MAGIC (0x9500)
-+#define EEPROM_MAC_OFFSET (0x01)
-+#define DEFAULT_TX_CSUM_ENABLE (true)
-+#define DEFAULT_RX_CSUM_ENABLE (true)
-+#define SMSC95XX_INTERNAL_PHY_ID (1)
-+#define SMSC95XX_TX_OVERHEAD (8)
-+#define SMSC95XX_TX_OVERHEAD_CSUM (12)
-+#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
-+ WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
-+
-+#define FEATURE_8_WAKEUP_FILTERS (0x01)
-+#define FEATURE_PHY_NLP_CROSSOVER (0x02)
-+#define FEATURE_REMOTE_WAKEUP (0x04)
-+
-+#define SUSPEND_SUSPEND0 (0x01)
-+#define SUSPEND_SUSPEND1 (0x02)
-+#define SUSPEND_SUSPEND2 (0x04)
-+#define SUSPEND_SUSPEND3 (0x08)
-+#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
-+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
-+
-+struct smsc95xx_priv {
-+ u32 mac_cr;
-+ u32 hash_hi;
-+ u32 hash_lo;
-+ u32 wolopts;
-+ spinlock_t mac_cr_lock;
-+ u8 features;
-+ u8 suspend_flags;
-+};
-+
-+static bool turbo_mode = true;
-+module_param(turbo_mode, bool, 0644);
-+MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
-+
-+static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
-+ u32 *data, int in_pm)
-+{
-+ u32 buf;
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_read_cmd;
-+ else
-+ fn = usbnet_read_cmd_nopm;
-+
-+ ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN
-+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, index, &buf, 4);
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n",
-+ index, ret);
-+
-+ le32_to_cpus(&buf);
-+ *data = buf;
-+
-+ return ret;
-+}
-+
-+static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index,
-+ u32 data, int in_pm)
-+{
-+ u32 buf;
-+ int ret;
-+ int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
-+
-+ BUG_ON(!dev);
-+
-+ if (!in_pm)
-+ fn = usbnet_write_cmd;
-+ else
-+ fn = usbnet_write_cmd_nopm;
-+
-+ buf = data;
-+ cpu_to_le32s(&buf);
-+
-+ ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT
-+ | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-+ 0, index, &buf, 4);
-+ if (unlikely(ret < 0))
-+ netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n",
-+ index, ret);
-+
-+ return ret;
-+}
-+
-+static int __must_check smsc95xx_read_reg_nopm(struct usbnet *dev, u32 index,
-+ u32 *data)
-+{
-+ return __smsc95xx_read_reg(dev, index, data, 1);
-+}
-+
-+static int __must_check smsc95xx_write_reg_nopm(struct usbnet *dev, u32 index,
-+ u32 data)
-+{
-+ return __smsc95xx_write_reg(dev, index, data, 1);
-+}
-+
-+static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
-+ u32 *data)
-+{
-+ return __smsc95xx_read_reg(dev, index, data, 0);
-+}
-+
-+static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
-+ u32 data)
-+{
-+ return __smsc95xx_write_reg(dev, index, data, 0);
-+}
-+
-+/* Loop until the read is completed with timeout
-+ * called with phy_mutex held */
-+static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev,
-+ int in_pm)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_ACCESS\n");
-+ return ret;
-+ }
-+
-+ if (!(val & MII_BUSY_))
-+ return 0;
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ return -EIO;
-+}
-+
-+static int __smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
-+ int in_pm)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u32 val, addr;
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ /* confirm MII not busy */
-+ ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n");
-+ goto done;
-+ }
-+
-+ /* set the address, index & direction (read from PHY) */
-+ phy_id &= dev->mii.phy_id_mask;
-+ idx &= dev->mii.reg_num_mask;
-+ addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_;
-+ ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_ADDR\n");
-+ goto done;
-+ }
-+
-+ ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
-+ goto done;
-+ }
-+
-+ ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading MII_DATA\n");
-+ goto done;
-+ }
-+
-+ ret = (u16)(val & 0xFFFF);
-+
-+done:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static void __smsc95xx_mdio_write(struct net_device *netdev, int phy_id,
-+ int idx, int regval, int in_pm)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u32 val, addr;
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ /* confirm MII not busy */
-+ ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n");
-+ goto done;
-+ }
-+
-+ val = regval;
-+ ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_DATA\n");
-+ goto done;
-+ }
-+
-+ /* set the address, index & direction (write to PHY) */
-+ phy_id &= dev->mii.phy_id_mask;
-+ idx &= dev->mii.reg_num_mask;
-+ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_;
-+ ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing MII_ADDR\n");
-+ goto done;
-+ }
-+
-+ ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
-+ goto done;
-+ }
-+
-+done:
-+ mutex_unlock(&dev->phy_mutex);
-+}
-+
-+static int smsc95xx_mdio_read_nopm(struct net_device *netdev, int phy_id,
-+ int idx)
-+{
-+ return __smsc95xx_mdio_read(netdev, phy_id, idx, 1);
-+}
-+
-+static void smsc95xx_mdio_write_nopm(struct net_device *netdev, int phy_id,
-+ int idx, int regval)
-+{
-+ __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 1);
-+}
-+
-+static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
-+{
-+ return __smsc95xx_mdio_read(netdev, phy_id, idx, 0);
-+}
-+
-+static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
-+ int regval)
-+{
-+ __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 0);
-+}
-+
-+static int __must_check smsc95xx_wait_eeprom(struct usbnet *dev)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = smsc95xx_read_reg(dev, E2P_CMD, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
-+ break;
-+ udelay(40);
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
-+ netdev_warn(dev->net, "EEPROM read operation timeout\n");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int __must_check smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
-+{
-+ unsigned long start_time = jiffies;
-+ u32 val;
-+ int ret;
-+
-+ do {
-+ ret = smsc95xx_read_reg(dev, E2P_CMD, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ if (!(val & E2P_CMD_BUSY_))
-+ return 0;
-+
-+ udelay(40);
-+ } while (!time_after(jiffies, start_time + HZ));
-+
-+ netdev_warn(dev->net, "EEPROM is busy\n");
-+ return -EIO;
-+}
-+
-+static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
-+ u8 *data)
-+{
-+ u32 val;
-+ int i, ret;
-+
-+ BUG_ON(!dev);
-+ BUG_ON(!data);
-+
-+ ret = smsc95xx_eeprom_confirm_not_busy(dev);
-+ if (ret)
-+ return ret;
-+
-+ for (i = 0; i < length; i++) {
-+ val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
-+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, E2P_DATA, &val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error reading E2P_DATA\n");
-+ return ret;
-+ }
-+
-+ data[i] = val & 0xFF;
-+ offset++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length,
-+ u8 *data)
-+{
-+ u32 val;
-+ int i, ret;
-+
-+ BUG_ON(!dev);
-+ BUG_ON(!data);
-+
-+ ret = smsc95xx_eeprom_confirm_not_busy(dev);
-+ if (ret)
-+ return ret;
-+
-+ /* Issue write/erase enable command */
-+ val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_;
-+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_DATA\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ for (i = 0; i < length; i++) {
-+
-+ /* Fill data register */
-+ val = data[i];
-+ ret = smsc95xx_write_reg(dev, E2P_DATA, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_DATA\n");
-+ return ret;
-+ }
-+
-+ /* Send "write" command */
-+ val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_);
-+ ret = smsc95xx_write_reg(dev, E2P_CMD, val);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Error writing E2P_CMD\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_wait_eeprom(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ offset++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int __must_check smsc95xx_write_reg_async(struct usbnet *dev, u16 index,
-+ u32 data)
-+{
-+ const u16 size = 4;
-+ u32 buf;
-+ int ret;
-+
-+ buf = data;
-+ cpu_to_le32s(&buf);
-+
-+ ret = usbnet_write_cmd_async(dev, USB_VENDOR_REQUEST_WRITE_REGISTER,
-+ USB_DIR_OUT | USB_TYPE_VENDOR |
-+ USB_RECIP_DEVICE,
-+ 0, index, &buf, size);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "Error write async cmd, sts=%d\n",
-+ ret);
-+ return ret;
-+}
-+
-+/* returns hash bit number for given MAC address
-+ * example:
-+ * 01 00 5E 00 00 01 -> returns bit number 31 */
-+static unsigned int smsc95xx_hash(char addr[ETH_ALEN])
-+{
-+ return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
-+}
-+
-+static void smsc95xx_set_multicast(struct net_device *netdev)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ unsigned long flags;
-+ int ret;
-+
-+ pdata->hash_hi = 0;
-+ pdata->hash_lo = 0;
-+
-+ spin_lock_irqsave(&pdata->mac_cr_lock, flags);
-+
-+ if (dev->net->flags & IFF_PROMISC) {
-+ netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n");
-+ pdata->mac_cr |= MAC_CR_PRMS_;
-+ pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
-+ } else if (dev->net->flags & IFF_ALLMULTI) {
-+ netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n");
-+ pdata->mac_cr |= MAC_CR_MCPAS_;
-+ pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_);
-+ } else if (!netdev_mc_empty(dev->net)) {
-+ struct netdev_hw_addr *ha;
-+
-+ pdata->mac_cr |= MAC_CR_HPFILT_;
-+ pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
-+
-+ netdev_for_each_mc_addr(ha, netdev) {
-+ u32 bitnum = smsc95xx_hash(ha->addr);
-+ u32 mask = 0x01 << (bitnum & 0x1F);
-+ if (bitnum & 0x20)
-+ pdata->hash_hi |= mask;
-+ else
-+ pdata->hash_lo |= mask;
-+ }
-+
-+ netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n",
-+ pdata->hash_hi, pdata->hash_lo);
-+ } else {
-+ netif_dbg(dev, drv, dev->net, "receive own packets only\n");
-+ pdata->mac_cr &=
-+ ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
-+ }
-+
-+ spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
-+
-+ /* Initiate async writes, as we can't wait for completion here */
-+ ret = smsc95xx_write_reg_async(dev, HASHH, pdata->hash_hi);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "failed to initiate async write to HASHH\n");
-+
-+ ret = smsc95xx_write_reg_async(dev, HASHL, pdata->hash_lo);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "failed to initiate async write to HASHL\n");
-+
-+ ret = smsc95xx_write_reg_async(dev, MAC_CR, pdata->mac_cr);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "failed to initiate async write to MAC_CR\n");
-+}
-+
-+static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
-+ u16 lcladv, u16 rmtadv)
-+{
-+ u32 flow, afc_cfg = 0;
-+
-+ int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (duplex == DUPLEX_FULL) {
-+ u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
-+
-+ if (cap & FLOW_CTRL_RX)
-+ flow = 0xFFFF0002;
-+ else
-+ flow = 0;
-+
-+ if (cap & FLOW_CTRL_TX)
-+ afc_cfg |= 0xF;
-+ else
-+ afc_cfg &= ~0xF;
-+
-+ netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n",
-+ cap & FLOW_CTRL_RX ? "enabled" : "disabled",
-+ cap & FLOW_CTRL_TX ? "enabled" : "disabled");
-+ } else {
-+ netif_dbg(dev, link, dev->net, "half duplex\n");
-+ flow = 0;
-+ afc_cfg |= 0xF;
-+ }
-+
-+ ret = smsc95xx_write_reg(dev, FLOW, flow);
-+ if (ret < 0)
-+ return ret;
-+
-+ return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg);
-+}
-+
-+static int smsc95xx_link_reset(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ struct mii_if_info *mii = &dev->mii;
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+ unsigned long flags;
-+ u16 lcladv, rmtadv;
-+ int ret;
-+
-+ /* clear interrupt status */
-+ ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-+ if (ret < 0)
-+ return ret;
-+
-+ mii_check_media(mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
-+ rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
-+
-+ netif_dbg(dev, link, dev->net,
-+ "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
-+ ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
-+
-+ spin_lock_irqsave(&pdata->mac_cr_lock, flags);
-+ if (ecmd.duplex != DUPLEX_FULL) {
-+ pdata->mac_cr &= ~MAC_CR_FDPX_;
-+ pdata->mac_cr |= MAC_CR_RCVOWN_;
-+ } else {
-+ pdata->mac_cr &= ~MAC_CR_RCVOWN_;
-+ pdata->mac_cr |= MAC_CR_FDPX_;
-+ }
-+ spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
-+
-+ ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "Error updating PHY flow control\n");
-+
-+ return ret;
-+}
-+
-+static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
-+{
-+ u32 intdata;
-+
-+ if (urb->actual_length != 4) {
-+ netdev_warn(dev->net, "unexpected urb length %d\n",
-+ urb->actual_length);
-+ return;
-+ }
-+
-+ memcpy(&intdata, urb->transfer_buffer, 4);
-+ le32_to_cpus(&intdata);
-+
-+ netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata);
-+
-+ if (intdata & INT_ENP_PHY_INT_)
-+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
-+ else
-+ netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n",
-+ intdata);
-+}
-+
-+/* Enable or disable Tx & Rx checksum offload engines */
-+static int smsc95xx_set_features(struct net_device *netdev,
-+ netdev_features_t features)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u32 read_buf;
-+ int ret;
-+
-+ ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (features & NETIF_F_HW_CSUM)
-+ read_buf |= Tx_COE_EN_;
-+ else
-+ read_buf &= ~Tx_COE_EN_;
-+
-+ if (features & NETIF_F_RXCSUM)
-+ read_buf |= Rx_COE_EN_;
-+ else
-+ read_buf &= ~Rx_COE_EN_;
-+
-+ ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
-+ return 0;
-+}
-+
-+static int smsc95xx_ethtool_get_eeprom_len(struct net_device *net)
-+{
-+ return MAX_EEPROM_SIZE;
-+}
-+
-+static int smsc95xx_ethtool_get_eeprom(struct net_device *netdev,
-+ struct ethtool_eeprom *ee, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ ee->magic = LAN95XX_EEPROM_MAGIC;
-+
-+ return smsc95xx_read_eeprom(dev, ee->offset, ee->len, data);
-+}
-+
-+static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev,
-+ struct ethtool_eeprom *ee, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ if (ee->magic != LAN95XX_EEPROM_MAGIC) {
-+ netdev_warn(dev->net, "EEPROM: magic value mismatch, magic = 0x%x\n",
-+ ee->magic);
-+ return -EINVAL;
-+ }
-+
-+ return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data);
-+}
-+
-+static int smsc95xx_ethtool_getregslen(struct net_device *netdev)
-+{
-+ /* all smsc95xx registers */
-+ return COE_CR - ID_REV + sizeof(u32);
-+}
-+
-+static void
-+smsc95xx_ethtool_getregs(struct net_device *netdev, struct ethtool_regs *regs,
-+ void *buf)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ unsigned int i, j;
-+ int retval;
-+ u32 *data = buf;
-+
-+ retval = smsc95xx_read_reg(dev, ID_REV, ®s->version);
-+ if (retval < 0) {
-+ netdev_warn(netdev, "REGS: cannot read ID_REV\n");
-+ return;
-+ }
-+
-+ for (i = ID_REV, j = 0; i <= COE_CR; i += (sizeof(u32)), j++) {
-+ retval = smsc95xx_read_reg(dev, i, &data[j]);
-+ if (retval < 0) {
-+ netdev_warn(netdev, "REGS: cannot read reg[%x]\n", i);
-+ return;
-+ }
-+ }
-+}
-+
-+static void smsc95xx_ethtool_get_wol(struct net_device *net,
-+ struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+
-+ wolinfo->supported = SUPPORTED_WAKE;
-+ wolinfo->wolopts = pdata->wolopts;
-+}
-+
-+static int smsc95xx_ethtool_set_wol(struct net_device *net,
-+ struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ int ret;
-+
-+ pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE;
-+
-+ ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret);
-+
-+ return ret;
-+}
-+
-+static const struct ethtool_ops smsc95xx_ethtool_ops = {
-+ .get_link = usbnet_get_link,
-+ .nway_reset = usbnet_nway_reset,
-+ .get_drvinfo = usbnet_get_drvinfo,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
-+ .get_eeprom = smsc95xx_ethtool_get_eeprom,
-+ .set_eeprom = smsc95xx_ethtool_set_eeprom,
-+ .get_regs_len = smsc95xx_ethtool_getregslen,
-+ .get_regs = smsc95xx_ethtool_getregs,
-+ .get_wol = smsc95xx_ethtool_get_wol,
-+ .set_wol = smsc95xx_ethtool_set_wol,
-+};
-+
-+static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ if (!netif_running(netdev))
-+ return -EINVAL;
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static void smsc95xx_init_mac_address(struct usbnet *dev)
-+{
-+ /* try reading mac address from EEPROM */
-+ if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
-+ dev->net->dev_addr) == 0) {
-+ if (is_valid_ether_addr(dev->net->dev_addr)) {
-+ /* eeprom values are valid so use them */
-+ netif_dbg(dev, ifup, dev->net, "MAC address read from EEPROM\n");
-+ return;
-+ }
-+ }
-+
-+ /* no eeprom, or eeprom values are invalid. generate random MAC */
-+ eth_hw_addr_random(dev->net);
-+ netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
-+}
-+
-+static int smsc95xx_set_mac_address(struct usbnet *dev)
-+{
-+ u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
-+ dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
-+ u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
-+ int ret;
-+
-+ ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
-+ if (ret < 0)
-+ return ret;
-+
-+ return smsc95xx_write_reg(dev, ADDRH, addr_hi);
-+}
-+
-+/* starts the TX path */
-+static int smsc95xx_start_tx_path(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ unsigned long flags;
-+ int ret;
-+
-+ /* Enable Tx at MAC */
-+ spin_lock_irqsave(&pdata->mac_cr_lock, flags);
-+ pdata->mac_cr |= MAC_CR_TXEN_;
-+ spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
-+
-+ ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Enable Tx at SCSRs */
-+ return smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_);
-+}
-+
-+/* Starts the Receive path */
-+static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&pdata->mac_cr_lock, flags);
-+ pdata->mac_cr |= MAC_CR_RXEN_;
-+ spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
-+
-+ return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
-+}
-+
-+static int smsc95xx_phy_initialize(struct usbnet *dev)
-+{
-+ int bmcr, ret, timeout = 0;
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = smsc95xx_mdio_read;
-+ dev->mii.mdio_write = smsc95xx_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID;
-+
-+ /* reset phy and wait for reset to complete */
-+ smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+
-+ do {
-+ msleep(10);
-+ bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR);
-+ timeout++;
-+ } while ((bmcr & BMCR_RESET) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout on PHY Reset");
-+ return -EIO;
-+ }
-+
-+ smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
-+ ADVERTISE_PAUSE_ASYM);
-+
-+ /* read to clear */
-+ ret = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to read PHY_INT_SRC during init\n");
-+ return ret;
-+ }
-+
-+ smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK,
-+ PHY_INT_MASK_DEFAULT_);
-+ mii_nway_restart(&dev->mii);
-+
-+ netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
-+ return 0;
-+}
-+
-+static int smsc95xx_reset(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ u32 read_buf, write_buf, burst_cap;
-+ int ret = 0, timeout;
-+
-+ netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n");
-+
-+ ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_);
-+ if (ret < 0)
-+ return ret;
-+
-+ timeout = 0;
-+ do {
-+ msleep(10);
-+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+ timeout++;
-+ } while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_);
-+ if (ret < 0)
-+ return ret;
-+
-+ timeout = 0;
-+ do {
-+ msleep(10);
-+ ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+ timeout++;
-+ } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
-+
-+ if (timeout >= 100) {
-+ netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_set_mac_address(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n",
-+ dev->net->dev_addr);
-+
-+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n",
-+ read_buf);
-+
-+ read_buf |= HW_CFG_BIR_;
-+
-+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
-+ read_buf);
-+
-+ if (!turbo_mode) {
-+ burst_cap = 0;
-+ dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
-+ } else if (dev->udev->speed == USB_SPEED_HIGH) {
-+ burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
-+ dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
-+ } else {
-+ burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
-+ dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
-+ (ulong)dev->rx_urb_size);
-+
-+ ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from BURST_CAP after writing: 0x%08x\n",
-+ read_buf);
-+
-+ ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from BULK_IN_DLY after writing: 0x%08x\n",
-+ read_buf);
-+
-+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG: 0x%08x\n",
-+ read_buf);
-+
-+ if (turbo_mode)
-+ read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
-+
-+ read_buf &= ~HW_CFG_RXDOFF_;
-+
-+ /* set Rx data offset=2, Make IP header aligns on word boundary. */
-+ read_buf |= NET_IP_ALIGN << 9;
-+
-+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ netif_dbg(dev, ifup, dev->net,
-+ "Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
-+
-+ ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+ netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
-+
-+ /* Configure GPIO pins as LED outputs */
-+ write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
-+ LED_GPIO_CFG_FDX_LED;
-+ ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Init Tx */
-+ ret = smsc95xx_write_reg(dev, FLOW, 0);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Don't need mac_cr_lock during initialisation */
-+ ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Init Rx */
-+ /* Set Vlan */
-+ ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Enable or disable checksum offload engines */
-+ ret = smsc95xx_set_features(dev->net, dev->net->features);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to set checksum offload features\n");
-+ return ret;
-+ }
-+
-+ smsc95xx_set_multicast(dev->net);
-+
-+ ret = smsc95xx_phy_initialize(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to init PHY\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* enable PHY interrupts */
-+ read_buf |= INT_EP_CTL_PHY_INT_;
-+
-+ ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_start_tx_path(dev);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to start TX path\n");
-+ return ret;
-+ }
-+
-+ ret = smsc95xx_start_rx_path(dev, 0);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "Failed to start RX path\n");
-+ return ret;
-+ }
-+
-+ netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n");
-+ return 0;
-+}
-+
-+static const struct net_device_ops smsc95xx_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = eth_mac_addr,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = smsc95xx_ioctl,
-+ .ndo_set_rx_mode = smsc95xx_set_multicast,
-+ .ndo_set_features = smsc95xx_set_features,
-+};
-+
-+static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct smsc95xx_priv *pdata = NULL;
-+ u32 val;
-+ int ret;
-+
-+ printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
-+
-+ ret = usbnet_get_endpoints(dev, intf);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
-+ return ret;
-+ }
-+
-+ dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv),
-+ GFP_KERNEL);
-+
-+ pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ if (!pdata)
-+ return -ENOMEM;
-+
-+ spin_lock_init(&pdata->mac_cr_lock);
-+
-+ if (DEFAULT_TX_CSUM_ENABLE)
-+ dev->net->features |= NETIF_F_HW_CSUM;
-+ if (DEFAULT_RX_CSUM_ENABLE)
-+ dev->net->features |= NETIF_F_RXCSUM;
-+
-+ dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
-+
-+ smsc95xx_init_mac_address(dev);
-+
-+ /* Init all registers */
-+ ret = smsc95xx_reset(dev);
-+
-+ /* detect device revision as different features may be available */
-+ ret = smsc95xx_read_reg(dev, ID_REV, &val);
-+ if (ret < 0)
-+ return ret;
-+ val >>= 16;
-+
-+ if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) ||
-+ (val == ID_REV_CHIP_ID_89530_) || (val == ID_REV_CHIP_ID_9730_))
-+ pdata->features = (FEATURE_8_WAKEUP_FILTERS |
-+ FEATURE_PHY_NLP_CROSSOVER |
-+ FEATURE_REMOTE_WAKEUP);
-+ else if (val == ID_REV_CHIP_ID_9512_)
-+ pdata->features = FEATURE_8_WAKEUP_FILTERS;
-+
-+ dev->net->netdev_ops = &smsc95xx_netdev_ops;
-+ dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
-+ dev->net->flags |= IFF_MULTICAST;
-+ dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
-+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-+ return 0;
-+}
-+
-+static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ if (pdata) {
-+ netif_dbg(dev, ifdown, dev->net, "free pdata\n");
-+ kfree(pdata);
-+ pdata = NULL;
-+ dev->data[0] = 0;
-+ }
-+}
-+
-+static u32 smsc_crc(const u8 *buffer, size_t len, int filter)
-+{
-+ u32 crc = bitrev16(crc16(0xFFFF, buffer, len));
-+ return crc << ((filter % 2) * 16);
-+}
-+
-+static int smsc95xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
-+{
-+ struct mii_if_info *mii = &dev->mii;
-+ int ret;
-+
-+ netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n");
-+
-+ /* read to clear */
-+ ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* enable interrupt source */
-+ ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret |= mask;
-+
-+ smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret);
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_link_ok_nopm(struct usbnet *dev)
-+{
-+ struct mii_if_info *mii = &dev->mii;
-+ int ret;
-+
-+ /* first, a dummy read, needed to latch some MII phys */
-+ ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
-+ if (ret < 0)
-+ return ret;
-+
-+ return !!(ret & BMSR_LSTATUS);
-+}
-+
-+static int smsc95xx_enter_suspend0(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
-+ val |= PM_CTL_SUS_MODE_0;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* clear wol status */
-+ val &= ~PM_CTL_WUPS_;
-+ val |= PM_CTL_WUPS_WOL_;
-+
-+ /* enable energy detection */
-+ if (pdata->wolopts & WAKE_PHY)
-+ val |= PM_CTL_WUPS_ED_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* read back PM_CTRL */
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND0;
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_enter_suspend1(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ struct mii_if_info *mii = &dev->mii;
-+ u32 val;
-+ int ret;
-+
-+ /* reconfigure link pulse detection timing for
-+ * compatibility with non-standard link partners
-+ */
-+ if (pdata->features & FEATURE_PHY_NLP_CROSSOVER)
-+ smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_EDPD_CONFIG,
-+ PHY_EDPD_CONFIG_DEFAULT);
-+
-+ /* enable energy detect power-down mode */
-+ ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS);
-+ if (ret < 0)
-+ return ret;
-+
-+ ret |= MODE_CTRL_STS_EDPWRDOWN_;
-+
-+ smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS, ret);
-+
-+ /* enter SUSPEND1 mode */
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
-+ val |= PM_CTL_SUS_MODE_1;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* clear wol status, enable energy detection */
-+ val &= ~PM_CTL_WUPS_;
-+ val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND1;
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_enter_suspend2(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
-+ val |= PM_CTL_SUS_MODE_2;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND2;
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_enter_suspend3(struct usbnet *dev)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ u32 val;
-+ int ret;
-+
-+ ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (val & 0xFFFF) {
-+ netdev_info(dev->net, "rx fifo not empty in autosuspend\n");
-+ return -EBUSY;
-+ }
-+
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
-+ val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* clear wol status */
-+ val &= ~PM_CTL_WUPS_;
-+ val |= PM_CTL_WUPS_WOL_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ pdata->suspend_flags |= SUSPEND_SUSPEND3;
-+
-+ return 0;
-+}
-+
-+static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ int ret;
-+
-+ if (!netif_running(dev->net)) {
-+ /* interface is ifconfig down so fully power down hw */
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n");
-+ return smsc95xx_enter_suspend2(dev);
-+ }
-+
-+ if (!link_up) {
-+ /* link is down so enter EDPD mode, but only if device can
-+ * reliably resume from it. This check should be redundant
-+ * as current FEATURE_REMOTE_WAKEUP parts also support
-+ * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */
-+ if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) {
-+ netdev_warn(dev->net, "EDPD not supported\n");
-+ return -EBUSY;
-+ }
-+
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n");
-+
-+ /* enable PHY wakeup events for if cable is attached */
-+ ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
-+ PHY_INT_MASK_ANEG_COMP_);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ return ret;
-+ }
-+
-+ netdev_info(dev->net, "entering SUSPEND1 mode\n");
-+ return smsc95xx_enter_suspend1(dev);
-+ }
-+
-+ /* enable PHY wakeup events so we remote wakeup if cable is pulled */
-+ ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
-+ PHY_INT_MASK_LINK_DOWN_);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ return ret;
-+ }
-+
-+ netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n");
-+ return smsc95xx_enter_suspend3(dev);
-+}
-+
-+static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ u32 val, link_up;
-+ int ret;
-+
-+ ret = usbnet_suspend(intf, message);
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "usbnet_suspend error\n");
-+ return ret;
-+ }
-+
-+ if (pdata->suspend_flags) {
-+ netdev_warn(dev->net, "error during last resume\n");
-+ pdata->suspend_flags = 0;
-+ }
-+
-+ /* determine if link is up using only _nopm functions */
-+ link_up = smsc95xx_link_ok_nopm(dev);
-+
-+ if (message.event == PM_EVENT_AUTO_SUSPEND &&
-+ (pdata->features & FEATURE_REMOTE_WAKEUP)) {
-+ ret = smsc95xx_autosuspend(dev, link_up);
-+ goto done;
-+ }
-+
-+ /* if we get this far we're not autosuspending */
-+ /* if no wol options set, or if link is down and we're not waking on
-+ * PHY activity, enter lowest power SUSPEND2 mode
-+ */
-+ if (!(pdata->wolopts & SUPPORTED_WAKE) ||
-+ !(link_up || (pdata->wolopts & WAKE_PHY))) {
-+ netdev_info(dev->net, "entering SUSPEND2 mode\n");
-+
-+ /* disable energy detect (link up) & wake up events */
-+ ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
-+
-+ ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0)
-+ goto done;
-+
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ goto done;
-+
-+ ret = smsc95xx_enter_suspend2(dev);
-+ goto done;
-+ }
-+
-+ if (pdata->wolopts & WAKE_PHY) {
-+ ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
-+ (PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_));
-+ if (ret < 0) {
-+ netdev_warn(dev->net, "error enabling PHY wakeup ints\n");
-+ goto done;
-+ }
-+
-+ /* if link is down then configure EDPD and enter SUSPEND1,
-+ * otherwise enter SUSPEND0 below
-+ */
-+ if (!link_up) {
-+ netdev_info(dev->net, "entering SUSPEND1 mode\n");
-+ ret = smsc95xx_enter_suspend1(dev);
-+ goto done;
-+ }
-+ }
-+
-+ if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
-+ u32 *filter_mask = kzalloc(sizeof(u32) * 32, GFP_KERNEL);
-+ u32 command[2];
-+ u32 offset[2];
-+ u32 crc[4];
-+ int wuff_filter_count =
-+ (pdata->features & FEATURE_8_WAKEUP_FILTERS) ?
-+ LAN9500A_WUFF_NUM : LAN9500_WUFF_NUM;
-+ int i, filter = 0;
-+
-+ if (!filter_mask) {
-+ netdev_warn(dev->net, "Unable to allocate filter_mask\n");
-+ ret = -ENOMEM;
-+ goto done;
-+ }
-+
-+ memset(command, 0, sizeof(command));
-+ memset(offset, 0, sizeof(offset));
-+ memset(crc, 0, sizeof(crc));
-+
-+ if (pdata->wolopts & WAKE_BCAST) {
-+ const u8 bcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-+ netdev_info(dev->net, "enabling broadcast detection\n");
-+ filter_mask[filter * 4] = 0x003F;
-+ filter_mask[filter * 4 + 1] = 0x00;
-+ filter_mask[filter * 4 + 2] = 0x00;
-+ filter_mask[filter * 4 + 3] = 0x00;
-+ command[filter/4] |= 0x05UL << ((filter % 4) * 8);
-+ offset[filter/4] |= 0x00 << ((filter % 4) * 8);
-+ crc[filter/2] |= smsc_crc(bcast, 6, filter);
-+ filter++;
-+ }
-+
-+ if (pdata->wolopts & WAKE_MCAST) {
-+ const u8 mcast[] = {0x01, 0x00, 0x5E};
-+ netdev_info(dev->net, "enabling multicast detection\n");
-+ filter_mask[filter * 4] = 0x0007;
-+ filter_mask[filter * 4 + 1] = 0x00;
-+ filter_mask[filter * 4 + 2] = 0x00;
-+ filter_mask[filter * 4 + 3] = 0x00;
-+ command[filter/4] |= 0x09UL << ((filter % 4) * 8);
-+ offset[filter/4] |= 0x00 << ((filter % 4) * 8);
-+ crc[filter/2] |= smsc_crc(mcast, 3, filter);
-+ filter++;
-+ }
-+
-+ if (pdata->wolopts & WAKE_ARP) {
-+ const u8 arp[] = {0x08, 0x06};
-+ netdev_info(dev->net, "enabling ARP detection\n");
-+ filter_mask[filter * 4] = 0x0003;
-+ filter_mask[filter * 4 + 1] = 0x00;
-+ filter_mask[filter * 4 + 2] = 0x00;
-+ filter_mask[filter * 4 + 3] = 0x00;
-+ command[filter/4] |= 0x05UL << ((filter % 4) * 8);
-+ offset[filter/4] |= 0x0C << ((filter % 4) * 8);
-+ crc[filter/2] |= smsc_crc(arp, 2, filter);
-+ filter++;
-+ }
-+
-+ if (pdata->wolopts & WAKE_UCAST) {
-+ netdev_info(dev->net, "enabling unicast detection\n");
-+ filter_mask[filter * 4] = 0x003F;
-+ filter_mask[filter * 4 + 1] = 0x00;
-+ filter_mask[filter * 4 + 2] = 0x00;
-+ filter_mask[filter * 4 + 3] = 0x00;
-+ command[filter/4] |= 0x01UL << ((filter % 4) * 8);
-+ offset[filter/4] |= 0x00 << ((filter % 4) * 8);
-+ crc[filter/2] |= smsc_crc(dev->net->dev_addr, ETH_ALEN, filter);
-+ filter++;
-+ }
-+
-+ for (i = 0; i < (wuff_filter_count * 4); i++) {
-+ ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
-+ if (ret < 0) {
-+ kfree(filter_mask);
-+ goto done;
-+ }
-+ }
-+ kfree(filter_mask);
-+
-+ for (i = 0; i < (wuff_filter_count / 4); i++) {
-+ ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
-+ if (ret < 0)
-+ goto done;
-+ }
-+
-+ for (i = 0; i < (wuff_filter_count / 4); i++) {
-+ ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
-+ if (ret < 0)
-+ goto done;
-+ }
-+
-+ for (i = 0; i < (wuff_filter_count / 2); i++) {
-+ ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
-+ if (ret < 0)
-+ goto done;
-+ }
-+
-+ /* clear any pending pattern match packet status */
-+ ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ val |= WUCSR_WUFR_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0)
-+ goto done;
-+ }
-+
-+ if (pdata->wolopts & WAKE_MAGIC) {
-+ /* clear any pending magic packet status */
-+ ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ val |= WUCSR_MPR_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0)
-+ goto done;
-+ }
-+
-+ /* enable/disable wakeup sources */
-+ ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
-+ netdev_info(dev->net, "enabling pattern match wakeup\n");
-+ val |= WUCSR_WAKE_EN_;
-+ } else {
-+ netdev_info(dev->net, "disabling pattern match wakeup\n");
-+ val &= ~WUCSR_WAKE_EN_;
-+ }
-+
-+ if (pdata->wolopts & WAKE_MAGIC) {
-+ netdev_info(dev->net, "enabling magic packet wakeup\n");
-+ val |= WUCSR_MPEN_;
-+ } else {
-+ netdev_info(dev->net, "disabling magic packet wakeup\n");
-+ val &= ~WUCSR_MPEN_;
-+ }
-+
-+ ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0)
-+ goto done;
-+
-+ /* enable wol wakeup source */
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ goto done;
-+
-+ val |= PM_CTL_WOL_EN_;
-+
-+ /* phy energy detect wakeup source */
-+ if (pdata->wolopts & WAKE_PHY)
-+ val |= PM_CTL_ED_EN_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ goto done;
-+
-+ /* enable receiver to enable frame reception */
-+ smsc95xx_start_rx_path(dev, 1);
-+
-+ /* some wol options are enabled, so enter SUSPEND0 */
-+ netdev_info(dev->net, "entering SUSPEND0 mode\n");
-+ ret = smsc95xx_enter_suspend0(dev);
-+
-+done:
-+ /*
-+ * TODO: resume() might need to handle the suspend failure
-+ * in system sleep
-+ */
-+ if (ret && PMSG_IS_AUTO(message))
-+ usbnet_resume(intf);
-+ return ret;
-+}
-+
-+static int smsc95xx_resume(struct usb_interface *intf)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ struct smsc95xx_priv *pdata;
-+ u8 suspend_flags;
-+ int ret;
-+ u32 val;
-+
-+ BUG_ON(!dev);
-+ pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+ suspend_flags = pdata->suspend_flags;
-+
-+ netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags);
-+
-+ /* do this first to ensure it's cleared even in error case */
-+ pdata->suspend_flags = 0;
-+
-+ if (suspend_flags & SUSPEND_ALLMODES) {
-+ /* clear wake-up sources */
-+ ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
-+
-+ ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* clear wake-up status */
-+ ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ val &= ~PM_CTL_WOL_EN_;
-+ val |= PM_CTL_WUPS_;
-+
-+ ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
-+ ret = usbnet_resume(intf);
-+ if (ret < 0)
-+ netdev_warn(dev->net, "usbnet_resume error\n");
-+
-+ return ret;
-+}
-+
-+static int smsc95xx_reset_resume(struct usb_interface *intf)
-+{
-+ struct usbnet *dev = usb_get_intfdata(intf);
-+ int ret;
-+
-+ ret = smsc95xx_reset(dev);
-+ if (ret < 0)
-+ return ret;
-+
-+ return smsc95xx_resume(intf);
-+}
-+
-+static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
-+{
-+ skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2);
-+ skb->ip_summed = CHECKSUM_COMPLETE;
-+ skb_trim(skb, skb->len - 2);
-+}
-+
-+static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ while (skb->len > 0) {
-+ u32 header, align_count;
-+ struct sk_buff *ax_skb;
-+ unsigned char *packet;
-+ u16 size;
-+
-+ memcpy(&header, skb->data, sizeof(header));
-+ le32_to_cpus(&header);
-+ skb_pull(skb, 4 + NET_IP_ALIGN);
-+ packet = skb->data;
-+
-+ /* get the packet length */
-+ size = (u16)((header & RX_STS_FL_) >> 16);
-+ align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
-+
-+ if (unlikely(header & RX_STS_ES_)) {
-+ netif_dbg(dev, rx_err, dev->net,
-+ "Error header=0x%08x\n", header);
-+ dev->net->stats.rx_errors++;
-+ dev->net->stats.rx_dropped++;
-+
-+ if (header & RX_STS_CRC_) {
-+ dev->net->stats.rx_crc_errors++;
-+ } else {
-+ if (header & (RX_STS_TL_ | RX_STS_RF_))
-+ dev->net->stats.rx_frame_errors++;
-+
-+ if ((header & RX_STS_LE_) &&
-+ (!(header & RX_STS_FT_)))
-+ dev->net->stats.rx_length_errors++;
-+ }
-+ } else {
-+ /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
-+ if (unlikely(size > (ETH_FRAME_LEN + 12))) {
-+ netif_dbg(dev, rx_err, dev->net,
-+ "size err header=0x%08x\n", header);
-+ return 0;
-+ }
-+
-+ /* last frame in this batch */
-+ if (skb->len == size) {
-+ if (dev->net->features & NETIF_F_RXCSUM)
-+ smsc95xx_rx_csum_offload(skb);
-+ skb_trim(skb, skb->len - 4); /* remove fcs */
-+ skb->truesize = size + sizeof(struct sk_buff);
-+
-+ return 1;
-+ }
-+
-+ ax_skb = skb_clone(skb, GFP_ATOMIC);
-+ if (unlikely(!ax_skb)) {
-+ netdev_warn(dev->net, "Error allocating skb\n");
-+ return 0;
-+ }
-+
-+ ax_skb->len = size;
-+ ax_skb->data = packet;
-+ skb_set_tail_pointer(ax_skb, size);
-+
-+ if (dev->net->features & NETIF_F_RXCSUM)
-+ smsc95xx_rx_csum_offload(ax_skb);
-+ skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
-+ ax_skb->truesize = size + sizeof(struct sk_buff);
-+
-+ usbnet_skb_return(dev, ax_skb);
-+ }
-+
-+ skb_pull(skb, size);
-+
-+ /* padding bytes before the next frame starts */
-+ if (skb->len)
-+ skb_pull(skb, align_count);
-+ }
-+
-+ if (unlikely(skb->len < 0)) {
-+ netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
-+{
-+ u16 low_16 = (u16)skb_checksum_start_offset(skb);
-+ u16 high_16 = low_16 + skb->csum_offset;
-+ return (high_16 << 16) | low_16;
-+}
-+
-+static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
-+ struct sk_buff *skb, gfp_t flags)
-+{
-+ bool csum = skb->ip_summed == CHECKSUM_PARTIAL;
-+ int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
-+ u32 tx_cmd_a, tx_cmd_b;
-+
-+ /* We do not advertise SG, so skbs should be already linearized */
-+ BUG_ON(skb_shinfo(skb)->nr_frags);
-+
-+ if (skb_headroom(skb) < overhead) {
-+ struct sk_buff *skb2 = skb_copy_expand(skb,
-+ overhead, 0, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ if (csum) {
-+ if (skb->len <= 45) {
-+ /* workaround - hardware tx checksum does not work
-+ * properly with extremely small packets */
-+ long csstart = skb_checksum_start_offset(skb);
-+ __wsum calc = csum_partial(skb->data + csstart,
-+ skb->len - csstart, 0);
-+ *((__sum16 *)(skb->data + csstart
-+ + skb->csum_offset)) = csum_fold(calc);
-+
-+ csum = false;
-+ } else {
-+ u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
-+ skb_push(skb, 4);
-+ cpu_to_le32s(&csum_preamble);
-+ memcpy(skb->data, &csum_preamble, 4);
-+ }
-+ }
-+
-+ skb_push(skb, 4);
-+ tx_cmd_b = (u32)(skb->len - 4);
-+ if (csum)
-+ tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
-+ cpu_to_le32s(&tx_cmd_b);
-+ memcpy(skb->data, &tx_cmd_b, 4);
-+
-+ skb_push(skb, 4);
-+ tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ |
-+ TX_CMD_A_LAST_SEG_;
-+ cpu_to_le32s(&tx_cmd_a);
-+ memcpy(skb->data, &tx_cmd_a, 4);
-+
-+ return skb;
-+}
-+
-+static int smsc95xx_manage_power(struct usbnet *dev, int on)
-+{
-+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-+
-+ dev->intf->needs_remote_wakeup = on;
-+
-+ if (pdata->features & FEATURE_REMOTE_WAKEUP)
-+ return 0;
-+
-+ /* this chip revision isn't capable of remote wakeup */
-+ netdev_info(dev->net, "hardware isn't capable of remote wakeup\n");
-+
-+ if (on)
-+ usb_autopm_get_interface_no_resume(dev->intf);
-+ else
-+ usb_autopm_put_interface(dev->intf);
-+
-+ return 0;
-+}
-+
-+static const struct driver_info smsc95xx_info = {
-+ .description = "smsc95xx USB 2.0 Ethernet",
-+ .bind = smsc95xx_bind,
-+ .unbind = smsc95xx_unbind,
-+ .link_reset = smsc95xx_link_reset,
-+ .reset = smsc95xx_reset,
-+ .rx_fixup = smsc95xx_rx_fixup,
-+ .tx_fixup = smsc95xx_tx_fixup,
-+ .status = smsc95xx_status,
-+ .manage_power = smsc95xx_manage_power,
-+ .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ /* SMSC9500 USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9500),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9505 USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9505),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500A USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9E00),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9505A USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9E01),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9512/9514 USB Hub & Ethernet Device */
-+ USB_DEVICE(0x0424, 0xec00),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500 USB Ethernet Device (SAL10) */
-+ USB_DEVICE(0x0424, 0x9900),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9505 USB Ethernet Device (SAL10) */
-+ USB_DEVICE(0x0424, 0x9901),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500A USB Ethernet Device (SAL10) */
-+ USB_DEVICE(0x0424, 0x9902),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9505A USB Ethernet Device (SAL10) */
-+ USB_DEVICE(0x0424, 0x9903),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9512/9514 USB Hub & Ethernet Device (SAL10) */
-+ USB_DEVICE(0x0424, 0x9904),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500A USB Ethernet Device (HAL) */
-+ USB_DEVICE(0x0424, 0x9905),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9505A USB Ethernet Device (HAL) */
-+ USB_DEVICE(0x0424, 0x9906),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500 USB Ethernet Device (Alternate ID) */
-+ USB_DEVICE(0x0424, 0x9907),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9500A USB Ethernet Device (Alternate ID) */
-+ USB_DEVICE(0x0424, 0x9908),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC9512/9514 USB Hub & Ethernet Device (Alternate ID) */
-+ USB_DEVICE(0x0424, 0x9909),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC LAN9530 USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9530),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC LAN9730 USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9730),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ {
-+ /* SMSC LAN89530 USB Ethernet Device */
-+ USB_DEVICE(0x0424, 0x9E08),
-+ .driver_info = (unsigned long) &smsc95xx_info,
-+ },
-+ { }, /* END */
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver smsc95xx_driver = {
-+ .name = "smsc95xx",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .suspend = smsc95xx_suspend,
-+ .resume = smsc95xx_resume,
-+ .reset_resume = smsc95xx_reset_resume,
-+ .disconnect = usbnet_disconnect,
-+ .disable_hub_initiated_lpm = 1,
-+ .supports_autosuspend = 1,
-+};
-+
-+module_usb_driver(smsc95xx_driver);
-+
-+MODULE_AUTHOR("Nancy Lin");
-+MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>");
-+MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/smsc95xx.h backports-4.2.6-1/drivers/net/usb/smsc95xx.h
---- backports-4.2.6-1.org/drivers/net/usb/smsc95xx.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/smsc95xx.h 2016-06-28 14:35:18.011973884 +0200
-@@ -0,0 +1,290 @@
-+ /***************************************************************************
-+ *
-+ * Copyright (C) 2007-2008 SMSC
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ *
-+ *****************************************************************************/
-+
-+#ifndef _SMSC95XX_H
-+#define _SMSC95XX_H
-+
-+/* Tx command words */
-+#define TX_CMD_A_DATA_OFFSET_ (0x001F0000)
-+#define TX_CMD_A_FIRST_SEG_ (0x00002000)
-+#define TX_CMD_A_LAST_SEG_ (0x00001000)
-+#define TX_CMD_A_BUF_SIZE_ (0x000007FF)
-+
-+#define TX_CMD_B_CSUM_ENABLE (0x00004000)
-+#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000)
-+#define TX_CMD_B_DISABLE_PADDING_ (0x00001000)
-+#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF)
-+
-+/* Rx status word */
-+#define RX_STS_FF_ (0x40000000) /* Filter Fail */
-+#define RX_STS_FL_ (0x3FFF0000) /* Frame Length */
-+#define RX_STS_ES_ (0x00008000) /* Error Summary */
-+#define RX_STS_BF_ (0x00002000) /* Broadcast Frame */
-+#define RX_STS_LE_ (0x00001000) /* Length Error */
-+#define RX_STS_RF_ (0x00000800) /* Runt Frame */
-+#define RX_STS_MF_ (0x00000400) /* Multicast Frame */
-+#define RX_STS_TL_ (0x00000080) /* Frame too long */
-+#define RX_STS_CS_ (0x00000040) /* Collision Seen */
-+#define RX_STS_FT_ (0x00000020) /* Frame Type */
-+#define RX_STS_RW_ (0x00000010) /* Receive Watchdog */
-+#define RX_STS_ME_ (0x00000008) /* Mii Error */
-+#define RX_STS_DB_ (0x00000004) /* Dribbling */
-+#define RX_STS_CRC_ (0x00000002) /* CRC Error */
-+
-+/* SCSRs */
-+#define ID_REV (0x00)
-+#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000)
-+#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
-+#define ID_REV_CHIP_ID_9500_ (0x9500)
-+#define ID_REV_CHIP_ID_9500A_ (0x9E00)
-+#define ID_REV_CHIP_ID_9512_ (0xEC00)
-+#define ID_REV_CHIP_ID_9530_ (0x9530)
-+#define ID_REV_CHIP_ID_89530_ (0x9E08)
-+#define ID_REV_CHIP_ID_9730_ (0x9730)
-+
-+#define INT_STS (0x08)
-+#define INT_STS_TX_STOP_ (0x00020000)
-+#define INT_STS_RX_STOP_ (0x00010000)
-+#define INT_STS_PHY_INT_ (0x00008000)
-+#define INT_STS_TXE_ (0x00004000)
-+#define INT_STS_TDFU_ (0x00002000)
-+#define INT_STS_TDFO_ (0x00001000)
-+#define INT_STS_RXDF_ (0x00000800)
-+#define INT_STS_GPIOS_ (0x000007FF)
-+#define INT_STS_CLEAR_ALL_ (0xFFFFFFFF)
-+
-+#define RX_CFG (0x0C)
-+#define RX_FIFO_FLUSH_ (0x00000001)
-+
-+#define TX_CFG (0x10)
-+#define TX_CFG_ON_ (0x00000004)
-+#define TX_CFG_STOP_ (0x00000002)
-+#define TX_CFG_FIFO_FLUSH_ (0x00000001)
-+
-+#define HW_CFG (0x14)
-+#define HW_CFG_BIR_ (0x00001000)
-+#define HW_CFG_LEDB_ (0x00000800)
-+#define HW_CFG_RXDOFF_ (0x00000600)
-+#define HW_CFG_DRP_ (0x00000040)
-+#define HW_CFG_MEF_ (0x00000020)
-+#define HW_CFG_LRST_ (0x00000008)
-+#define HW_CFG_PSEL_ (0x00000004)
-+#define HW_CFG_BCE_ (0x00000002)
-+#define HW_CFG_SRST_ (0x00000001)
-+
-+#define RX_FIFO_INF (0x18)
-+
-+#define PM_CTRL (0x20)
-+#define PM_CTL_RES_CLR_WKP_STS (0x00000200)
-+#define PM_CTL_DEV_RDY_ (0x00000080)
-+#define PM_CTL_SUS_MODE_ (0x00000060)
-+#define PM_CTL_SUS_MODE_0 (0x00000000)
-+#define PM_CTL_SUS_MODE_1 (0x00000020)
-+#define PM_CTL_SUS_MODE_2 (0x00000040)
-+#define PM_CTL_SUS_MODE_3 (0x00000060)
-+#define PM_CTL_PHY_RST_ (0x00000010)
-+#define PM_CTL_WOL_EN_ (0x00000008)
-+#define PM_CTL_ED_EN_ (0x00000004)
-+#define PM_CTL_WUPS_ (0x00000003)
-+#define PM_CTL_WUPS_NO_ (0x00000000)
-+#define PM_CTL_WUPS_ED_ (0x00000001)
-+#define PM_CTL_WUPS_WOL_ (0x00000002)
-+#define PM_CTL_WUPS_MULTI_ (0x00000003)
-+
-+#define LED_GPIO_CFG (0x24)
-+#define LED_GPIO_CFG_SPD_LED (0x01000000)
-+#define LED_GPIO_CFG_LNK_LED (0x00100000)
-+#define LED_GPIO_CFG_FDX_LED (0x00010000)
-+
-+#define GPIO_CFG (0x28)
-+
-+#define AFC_CFG (0x2C)
-+
-+/* Hi watermark = 15.5Kb (~10 mtu pkts) */
-+/* low watermark = 3k (~2 mtu pkts) */
-+/* backpressure duration = ~ 350us */
-+/* Apply FC on any frame. */
-+#define AFC_CFG_DEFAULT (0x00F830A1)
-+
-+#define E2P_CMD (0x30)
-+#define E2P_CMD_BUSY_ (0x80000000)
-+#define E2P_CMD_MASK_ (0x70000000)
-+#define E2P_CMD_READ_ (0x00000000)
-+#define E2P_CMD_EWDS_ (0x10000000)
-+#define E2P_CMD_EWEN_ (0x20000000)
-+#define E2P_CMD_WRITE_ (0x30000000)
-+#define E2P_CMD_WRAL_ (0x40000000)
-+#define E2P_CMD_ERASE_ (0x50000000)
-+#define E2P_CMD_ERAL_ (0x60000000)
-+#define E2P_CMD_RELOAD_ (0x70000000)
-+#define E2P_CMD_TIMEOUT_ (0x00000400)
-+#define E2P_CMD_LOADED_ (0x00000200)
-+#define E2P_CMD_ADDR_ (0x000001FF)
-+
-+#define MAX_EEPROM_SIZE (512)
-+
-+#define E2P_DATA (0x34)
-+#define E2P_DATA_MASK_ (0x000000FF)
-+
-+#define BURST_CAP (0x38)
-+
-+#define GPIO_WAKE (0x64)
-+
-+#define INT_EP_CTL (0x68)
-+#define INT_EP_CTL_INTEP_ (0x80000000)
-+#define INT_EP_CTL_MACRTO_ (0x00080000)
-+#define INT_EP_CTL_TX_STOP_ (0x00020000)
-+#define INT_EP_CTL_RX_STOP_ (0x00010000)
-+#define INT_EP_CTL_PHY_INT_ (0x00008000)
-+#define INT_EP_CTL_TXE_ (0x00004000)
-+#define INT_EP_CTL_TDFU_ (0x00002000)
-+#define INT_EP_CTL_TDFO_ (0x00001000)
-+#define INT_EP_CTL_RXDF_ (0x00000800)
-+#define INT_EP_CTL_GPIOS_ (0x000007FF)
-+
-+#define BULK_IN_DLY (0x6C)
-+
-+/* MAC CSRs */
-+#define MAC_CR (0x100)
-+#define MAC_CR_RXALL_ (0x80000000)
-+#define MAC_CR_RCVOWN_ (0x00800000)
-+#define MAC_CR_LOOPBK_ (0x00200000)
-+#define MAC_CR_FDPX_ (0x00100000)
-+#define MAC_CR_MCPAS_ (0x00080000)
-+#define MAC_CR_PRMS_ (0x00040000)
-+#define MAC_CR_INVFILT_ (0x00020000)
-+#define MAC_CR_PASSBAD_ (0x00010000)
-+#define MAC_CR_HFILT_ (0x00008000)
-+#define MAC_CR_HPFILT_ (0x00002000)
-+#define MAC_CR_LCOLL_ (0x00001000)
-+#define MAC_CR_BCAST_ (0x00000800)
-+#define MAC_CR_DISRTY_ (0x00000400)
-+#define MAC_CR_PADSTR_ (0x00000100)
-+#define MAC_CR_BOLMT_MASK (0x000000C0)
-+#define MAC_CR_DFCHK_ (0x00000020)
-+#define MAC_CR_TXEN_ (0x00000008)
-+#define MAC_CR_RXEN_ (0x00000004)
-+
-+#define ADDRH (0x104)
-+
-+#define ADDRL (0x108)
-+
-+#define HASHH (0x10C)
-+
-+#define HASHL (0x110)
-+
-+#define MII_ADDR (0x114)
-+#define MII_WRITE_ (0x02)
-+#define MII_BUSY_ (0x01)
-+#define MII_READ_ (0x00) /* ~of MII Write bit */
-+
-+#define MII_DATA (0x118)
-+
-+#define FLOW (0x11C)
-+#define FLOW_FCPT_ (0xFFFF0000)
-+#define FLOW_FCPASS_ (0x00000004)
-+#define FLOW_FCEN_ (0x00000002)
-+#define FLOW_FCBSY_ (0x00000001)
-+
-+#define VLAN1 (0x120)
-+
-+#define VLAN2 (0x124)
-+
-+#define WUFF (0x128)
-+#define LAN9500_WUFF_NUM (4)
-+#define LAN9500A_WUFF_NUM (8)
-+
-+#define WUCSR (0x12C)
-+#define WUCSR_WFF_PTR_RST_ (0x80000000)
-+#define WUCSR_GUE_ (0x00000200)
-+#define WUCSR_WUFR_ (0x00000040)
-+#define WUCSR_MPR_ (0x00000020)
-+#define WUCSR_WAKE_EN_ (0x00000004)
-+#define WUCSR_MPEN_ (0x00000002)
-+
-+#define COE_CR (0x130)
-+#define Tx_COE_EN_ (0x00010000)
-+#define Rx_COE_MODE_ (0x00000002)
-+#define Rx_COE_EN_ (0x00000001)
-+
-+/* Vendor-specific PHY Definitions */
-+
-+/* EDPD NLP / crossover time configuration (LAN9500A only) */
-+#define PHY_EDPD_CONFIG (16)
-+#define PHY_EDPD_CONFIG_TX_NLP_EN_ ((u16)0x8000)
-+#define PHY_EDPD_CONFIG_TX_NLP_1000_ ((u16)0x0000)
-+#define PHY_EDPD_CONFIG_TX_NLP_768_ ((u16)0x2000)
-+#define PHY_EDPD_CONFIG_TX_NLP_512_ ((u16)0x4000)
-+#define PHY_EDPD_CONFIG_TX_NLP_256_ ((u16)0x6000)
-+#define PHY_EDPD_CONFIG_RX_1_NLP_ ((u16)0x1000)
-+#define PHY_EDPD_CONFIG_RX_NLP_64_ ((u16)0x0000)
-+#define PHY_EDPD_CONFIG_RX_NLP_256_ ((u16)0x0400)
-+#define PHY_EDPD_CONFIG_RX_NLP_512_ ((u16)0x0800)
-+#define PHY_EDPD_CONFIG_RX_NLP_1000_ ((u16)0x0C00)
-+#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ ((u16)0x0001)
-+#define PHY_EDPD_CONFIG_DEFAULT (PHY_EDPD_CONFIG_TX_NLP_EN_ | \
-+ PHY_EDPD_CONFIG_TX_NLP_768_ | \
-+ PHY_EDPD_CONFIG_RX_1_NLP_)
-+
-+/* Mode Control/Status Register */
-+#define PHY_MODE_CTRL_STS (17)
-+#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000)
-+#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002)
-+
-+#define SPECIAL_CTRL_STS (27)
-+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((u16)0x8000)
-+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((u16)0x4000)
-+#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((u16)0x2000)
-+
-+#define PHY_INT_SRC (29)
-+#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080)
-+#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040)
-+#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020)
-+#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010)
-+
-+#define PHY_INT_MASK (30)
-+#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080)
-+#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040)
-+#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020)
-+#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010)
-+#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \
-+ PHY_INT_MASK_LINK_DOWN_)
-+
-+#define PHY_SPECIAL (31)
-+#define PHY_SPECIAL_SPD_ ((u16)0x001C)
-+#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004)
-+#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014)
-+#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008)
-+#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018)
-+
-+/* USB Vendor Requests */
-+#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0
-+#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1
-+#define USB_VENDOR_REQUEST_GET_STATS 0xA2
-+
-+/* Interrupt Endpoint status word bitfields */
-+#define INT_ENP_TX_STOP_ ((u32)BIT(17))
-+#define INT_ENP_RX_STOP_ ((u32)BIT(16))
-+#define INT_ENP_PHY_INT_ ((u32)BIT(15))
-+#define INT_ENP_TXE_ ((u32)BIT(14))
-+#define INT_ENP_TDFU_ ((u32)BIT(13))
-+#define INT_ENP_TDFO_ ((u32)BIT(12))
-+#define INT_ENP_RXDF_ ((u32)BIT(11))
-+
-+#endif /* _SMSC95XX_H */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/sr9700.c backports-4.2.6-1/drivers/net/usb/sr9700.c
---- backports-4.2.6-1.org/drivers/net/usb/sr9700.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/sr9700.c 2016-06-28 14:35:18.011973884 +0200
-@@ -0,0 +1,559 @@
-+/*
-+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
-+ *
-+ * Author : Liu Junliang <liujunliang_ljl@163.com>
-+ *
-+ * Based on dm9601.c
-+ *
-+ * This file is licensed under the terms of the GNU General Public License
-+ * version 2. This program is licensed "as is" without any warranty of any
-+ * kind, whether express or implied.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/stddef.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+
-+#include "sr9700.h"
-+
-+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ int err;
-+
-+ err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
-+ length);
-+ if ((err != length) && (err >= 0))
-+ err = -EINVAL;
-+ return err;
-+}
-+
-+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ int err;
-+
-+ err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data,
-+ length);
-+ if ((err >= 0) && (err < length))
-+ err = -EINVAL;
-+ return err;
-+}
-+
-+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
-+{
-+ return sr_read(dev, reg, 1, value);
-+}
-+
-+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
-+{
-+ return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
-+ value, reg, NULL, 0);
-+}
-+
-+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
-+{
-+ usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
-+ 0, reg, data, length);
-+}
-+
-+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
-+{
-+ usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
-+ value, reg, NULL, 0);
-+}
-+
-+static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
-+{
-+ int i;
-+
-+ for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
-+ u8 tmp = 0;
-+ int ret;
-+
-+ udelay(1);
-+ ret = sr_read_reg(dev, SR_EPCR, &tmp);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* ready */
-+ if (!(tmp & EPCR_ERRE))
-+ return 0;
-+ }
-+
-+ netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
-+
-+ return -EIO;
-+}
-+
-+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
-+ __le16 *value)
-+{
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
-+ sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
-+
-+ ret = wait_phy_eeprom_ready(dev, phy);
-+ if (ret < 0)
-+ goto out_unlock;
-+
-+ sr_write_reg(dev, SR_EPCR, 0x0);
-+ ret = sr_read(dev, SR_EPDR, 2, value);
-+
-+ netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
-+ phy, reg, *value, ret);
-+
-+out_unlock:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
-+ __le16 value)
-+{
-+ int ret;
-+
-+ mutex_lock(&dev->phy_mutex);
-+
-+ ret = sr_write(dev, SR_EPDR, 2, &value);
-+ if (ret < 0)
-+ goto out_unlock;
-+
-+ sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
-+ sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) :
-+ (EPCR_WEP | EPCR_ERPRW));
-+
-+ ret = wait_phy_eeprom_ready(dev, phy);
-+ if (ret < 0)
-+ goto out_unlock;
-+
-+ sr_write_reg(dev, SR_EPCR, 0x0);
-+
-+out_unlock:
-+ mutex_unlock(&dev->phy_mutex);
-+ return ret;
-+}
-+
-+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
-+{
-+ return sr_share_read_word(dev, 0, offset, value);
-+}
-+
-+static int sr9700_get_eeprom_len(struct net_device *netdev)
-+{
-+ return SR_EEPROM_LEN;
-+}
-+
-+static int sr9700_get_eeprom(struct net_device *netdev,
-+ struct ethtool_eeprom *eeprom, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 *buf = (__le16 *)data;
-+ int ret = 0;
-+ int i;
-+
-+ /* access is 16bit */
-+ if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
-+ return -EINVAL;
-+
-+ for (i = 0; i < eeprom->len / 2; i++) {
-+ ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i);
-+ if (ret < 0)
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 res;
-+ int rc = 0;
-+
-+ if (phy_id) {
-+ netdev_dbg(netdev, "Only internal phy supported\n");
-+ return 0;
-+ }
-+
-+ /* Access NSR_LINKST bit for link status instead of MII_BMSR */
-+ if (loc == MII_BMSR) {
-+ u8 value;
-+
-+ sr_read_reg(dev, SR_NSR, &value);
-+ if (value & NSR_LINKST)
-+ rc = 1;
-+ }
-+ sr_share_read_word(dev, 1, loc, &res);
-+ if (rc == 1)
-+ res = le16_to_cpu(res) | BMSR_LSTATUS;
-+ else
-+ res = le16_to_cpu(res) & ~BMSR_LSTATUS;
-+
-+ netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
-+ phy_id, loc, res);
-+
-+ return res;
-+}
-+
-+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
-+ int val)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ __le16 res = cpu_to_le16(val);
-+
-+ if (phy_id) {
-+ netdev_dbg(netdev, "Only internal phy supported\n");
-+ return;
-+ }
-+
-+ netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
-+ phy_id, loc, val);
-+
-+ sr_share_write_word(dev, 1, loc, res);
-+}
-+
-+static u32 sr9700_get_link(struct net_device *netdev)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ u8 value = 0;
-+ int rc = 0;
-+
-+ /* Get the Link Status directly */
-+ sr_read_reg(dev, SR_NSR, &value);
-+ if (value & NSR_LINKST)
-+ rc = 1;
-+
-+ return rc;
-+}
-+
-+static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static const struct ethtool_ops sr9700_ethtool_ops = {
-+ .get_drvinfo = usbnet_get_drvinfo,
-+ .get_link = sr9700_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_eeprom_len = sr9700_get_eeprom_len,
-+ .get_eeprom = sr9700_get_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static void sr9700_set_multicast(struct net_device *netdev)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ /* We use the 20 byte dev->data for our 8 byte filter buffer
-+ * to avoid allocating memory that is tricky to free later
-+ */
-+ u8 *hashes = (u8 *)&dev->data;
-+ /* rx_ctl setting : enable, disable_long, disable_crc */
-+ u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
-+
-+ memset(hashes, 0x00, SR_MCAST_SIZE);
-+ /* broadcast address */
-+ hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
-+ if (netdev->flags & IFF_PROMISC) {
-+ rx_ctl |= RCR_PRMSC;
-+ } else if (netdev->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(netdev) > SR_MCAST_MAX) {
-+ rx_ctl |= RCR_RUNT;
-+ } else if (!netdev_mc_empty(netdev)) {
-+ struct netdev_hw_addr *ha;
-+
-+ netdev_for_each_mc_addr(ha, netdev) {
-+ u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ hashes[crc >> 3] |= 1 << (crc & 0x7);
-+ }
-+ }
-+
-+ sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
-+ sr_write_reg_async(dev, SR_RCR, rx_ctl);
-+}
-+
-+static int sr9700_set_mac_address(struct net_device *netdev, void *p)
-+{
-+ struct usbnet *dev = netdev_priv(netdev);
-+ struct sockaddr *addr = p;
-+
-+ if (!is_valid_ether_addr(addr->sa_data)) {
-+ netdev_err(netdev, "not setting invalid mac address %pM\n",
-+ addr->sa_data);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-+ sr_write_async(dev, SR_PAR, 6, netdev->dev_addr);
-+
-+ return 0;
-+}
-+
-+static const struct net_device_ops sr9700_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = sr9700_ioctl,
-+ .ndo_set_rx_mode = sr9700_set_multicast,
-+ .ndo_set_mac_address = sr9700_set_mac_address,
-+};
-+
-+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct net_device *netdev;
-+ struct mii_if_info *mii;
-+ int ret;
-+
-+ ret = usbnet_get_endpoints(dev, intf);
-+ if (ret)
-+ goto out;
-+
-+ netdev = dev->net;
-+
-+ netdev->netdev_ops = &sr9700_netdev_ops;
-+ netdev->ethtool_ops = &sr9700_ethtool_ops;
-+ netdev->hard_header_len += SR_TX_OVERHEAD;
-+ dev->hard_mtu = netdev->mtu + netdev->hard_header_len;
-+ /* bulkin buffer is preferably not less than 3K */
-+ dev->rx_urb_size = 3072;
-+
-+ mii = &dev->mii;
-+ mii->dev = netdev;
-+ mii->mdio_read = sr_mdio_read;
-+ mii->mdio_write = sr_mdio_write;
-+ mii->phy_id_mask = 0x1f;
-+ mii->reg_num_mask = 0x1f;
-+
-+ sr_write_reg(dev, SR_NCR, NCR_RST);
-+ udelay(20);
-+
-+ /* read MAC
-+ * After Chip Power on, the Chip will reload the MAC from
-+ * EEPROM automatically to PAR. In case there is no EEPROM externally,
-+ * a default MAC address is stored in PAR for making chip work properly.
-+ */
-+ if (sr_read(dev, SR_PAR, ETH_ALEN, netdev->dev_addr) < 0) {
-+ netdev_err(netdev, "Error reading MAC address\n");
-+ ret = -ENODEV;
-+ goto out;
-+ }
-+
-+ /* power up and reset phy */
-+ sr_write_reg(dev, SR_PRR, PRR_PHY_RST);
-+ /* at least 10ms, here 20ms for safe */
-+ mdelay(20);
-+ sr_write_reg(dev, SR_PRR, 0);
-+ /* at least 1ms, here 2ms for reading right register */
-+ udelay(2 * 1000);
-+
-+ /* receive broadcast packets */
-+ sr9700_set_multicast(netdev);
-+
-+ sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
-+ sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
-+ ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
-+ mii_nway_restart(mii);
-+
-+out:
-+ return ret;
-+}
-+
-+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ struct sk_buff *sr_skb;
-+ int len;
-+
-+ /* skb content (packets) format :
-+ * p0 p1 p2 ...... pm
-+ * / \
-+ * / \
-+ * / \
-+ * / \
-+ * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
-+ *
-+ * p0 : packet 0
-+ * p0b0 : packet 0 byte 0
-+ *
-+ * b0: rx status
-+ * b1: packet length (incl crc) low
-+ * b2: packet length (incl crc) high
-+ * b3..n-4: packet data
-+ * bn-3..bn: ethernet packet crc
-+ */
-+ if (unlikely(skb->len < SR_RX_OVERHEAD)) {
-+ netdev_err(dev->net, "unexpected tiny rx frame\n");
-+ return 0;
-+ }
-+
-+ /* one skb may contains multiple packets */
-+ while (skb->len > SR_RX_OVERHEAD) {
-+ if (skb->data[0] != 0x40)
-+ return 0;
-+
-+ /* ignore the CRC length */
-+ len = (skb->data[1] | (skb->data[2] << 8)) - 4;
-+
-+ if (len > ETH_FRAME_LEN)
-+ return 0;
-+
-+ /* the last packet of current skb */
-+ if (skb->len == (len + SR_RX_OVERHEAD)) {
-+ skb_pull(skb, 3);
-+ skb->len = len;
-+ skb_set_tail_pointer(skb, len);
-+ skb->truesize = len + sizeof(struct sk_buff);
-+ return 2;
-+ }
-+
-+ /* skb_clone is used for address align */
-+ sr_skb = skb_clone(skb, GFP_ATOMIC);
-+ if (!sr_skb)
-+ return 0;
-+
-+ sr_skb->len = len;
-+ sr_skb->data = skb->data + 3;
-+ skb_set_tail_pointer(sr_skb, len);
-+ sr_skb->truesize = len + sizeof(struct sk_buff);
-+ usbnet_skb_return(dev, sr_skb);
-+
-+ skb_pull(skb, len + SR_RX_OVERHEAD);
-+ };
-+
-+ return 0;
-+}
-+
-+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ int len;
-+
-+ /* SR9700 can only send out one ethernet packet at once.
-+ *
-+ * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
-+ *
-+ * b0: rx status
-+ * b1: packet length (incl crc) low
-+ * b2: packet length (incl crc) high
-+ * b3..n-4: packet data
-+ * bn-3..bn: ethernet packet crc
-+ */
-+
-+ len = skb->len;
-+
-+ if (skb_headroom(skb) < SR_TX_OVERHEAD) {
-+ struct sk_buff *skb2;
-+
-+ skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ __skb_push(skb, SR_TX_OVERHEAD);
-+
-+ /* usbnet adds padding if length is a multiple of packet size
-+ * if so, adjust length value in header
-+ */
-+ if ((skb->len % dev->maxpacket) == 0)
-+ len++;
-+
-+ skb->data[0] = len;
-+ skb->data[1] = len >> 8;
-+
-+ return skb;
-+}
-+
-+static void sr9700_status(struct usbnet *dev, struct urb *urb)
-+{
-+ int link;
-+ u8 *buf;
-+
-+ /* format:
-+ b0: net status
-+ b1: tx status 1
-+ b2: tx status 2
-+ b3: rx status
-+ b4: rx overflow
-+ b5: rx count
-+ b6: tx count
-+ b7: gpr
-+ */
-+
-+ if (urb->actual_length < 8)
-+ return;
-+
-+ buf = urb->transfer_buffer;
-+
-+ link = !!(buf[0] & 0x40);
-+ if (netif_carrier_ok(dev->net) != link) {
-+ usbnet_link_change(dev, link, 1);
-+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
-+ }
-+}
-+
-+static int sr9700_link_reset(struct usbnet *dev)
-+{
-+ struct ethtool_cmd ecmd;
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+
-+ netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
-+ ecmd.speed, ecmd.duplex);
-+
-+ return 0;
-+}
-+
-+static const struct driver_info sr9700_driver_info = {
-+ .description = "CoreChip SR9700 USB Ethernet",
-+ .flags = FLAG_ETHER,
-+ .bind = sr9700_bind,
-+ .rx_fixup = sr9700_rx_fixup,
-+ .tx_fixup = sr9700_tx_fixup,
-+ .status = sr9700_status,
-+ .link_reset = sr9700_link_reset,
-+ .reset = sr9700_link_reset,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */
-+ .driver_info = (unsigned long)&sr9700_driver_info,
-+ },
-+ {}, /* END */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver sr9700_usb_driver = {
-+ .name = "sr9700",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(sr9700_usb_driver);
-+
-+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
-+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/sr9700.h backports-4.2.6-1/drivers/net/usb/sr9700.h
---- backports-4.2.6-1.org/drivers/net/usb/sr9700.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/sr9700.h 2016-06-28 14:35:18.011973884 +0200
-@@ -0,0 +1,173 @@
-+/*
-+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
-+ *
-+ * Author : Liu Junliang <liujunliang_ljl@163.com>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * version 2 as published by the Free Software Foundation.
-+ */
-+
-+#ifndef _SR9700_H
-+#define _SR9700_H
-+
-+/* sr9700 spec. register table on Linux platform */
-+
-+/* Network Control Reg */
-+#define SR_NCR 0x00
-+#define NCR_RST (1 << 0)
-+#define NCR_LBK (3 << 1)
-+#define NCR_FDX (1 << 3)
-+#define NCR_WAKEEN (1 << 6)
-+/* Network Status Reg */
-+#define SR_NSR 0x01
-+#define NSR_RXRDY (1 << 0)
-+#define NSR_RXOV (1 << 1)
-+#define NSR_TX1END (1 << 2)
-+#define NSR_TX2END (1 << 3)
-+#define NSR_TXFULL (1 << 4)
-+#define NSR_WAKEST (1 << 5)
-+#define NSR_LINKST (1 << 6)
-+#define NSR_SPEED (1 << 7)
-+/* Tx Control Reg */
-+#define SR_TCR 0x02
-+#define TCR_CRC_DIS (1 << 1)
-+#define TCR_PAD_DIS (1 << 2)
-+#define TCR_LC_CARE (1 << 3)
-+#define TCR_CRS_CARE (1 << 4)
-+#define TCR_EXCECM (1 << 5)
-+#define TCR_LF_EN (1 << 6)
-+/* Tx Status Reg for Packet Index 1 */
-+#define SR_TSR1 0x03
-+#define TSR1_EC (1 << 2)
-+#define TSR1_COL (1 << 3)
-+#define TSR1_LC (1 << 4)
-+#define TSR1_NC (1 << 5)
-+#define TSR1_LOC (1 << 6)
-+#define TSR1_TLF (1 << 7)
-+/* Tx Status Reg for Packet Index 2 */
-+#define SR_TSR2 0x04
-+#define TSR2_EC (1 << 2)
-+#define TSR2_COL (1 << 3)
-+#define TSR2_LC (1 << 4)
-+#define TSR2_NC (1 << 5)
-+#define TSR2_LOC (1 << 6)
-+#define TSR2_TLF (1 << 7)
-+/* Rx Control Reg*/
-+#define SR_RCR 0x05
-+#define RCR_RXEN (1 << 0)
-+#define RCR_PRMSC (1 << 1)
-+#define RCR_RUNT (1 << 2)
-+#define RCR_ALL (1 << 3)
-+#define RCR_DIS_CRC (1 << 4)
-+#define RCR_DIS_LONG (1 << 5)
-+/* Rx Status Reg */
-+#define SR_RSR 0x06
-+#define RSR_AE (1 << 2)
-+#define RSR_MF (1 << 6)
-+#define RSR_RF (1 << 7)
-+/* Rx Overflow Counter Reg */
-+#define SR_ROCR 0x07
-+#define ROCR_ROC (0x7F << 0)
-+#define ROCR_RXFU (1 << 7)
-+/* Back Pressure Threshold Reg */
-+#define SR_BPTR 0x08
-+#define BPTR_JPT (0x0F << 0)
-+#define BPTR_BPHW (0x0F << 4)
-+/* Flow Control Threshold Reg */
-+#define SR_FCTR 0x09
-+#define FCTR_LWOT (0x0F << 0)
-+#define FCTR_HWOT (0x0F << 4)
-+/* rx/tx Flow Control Reg */
-+#define SR_FCR 0x0A
-+#define FCR_FLCE (1 << 0)
-+#define FCR_BKPA (1 << 4)
-+#define FCR_TXPEN (1 << 5)
-+#define FCR_TXPF (1 << 6)
-+#define FCR_TXP0 (1 << 7)
-+/* Eeprom & Phy Control Reg */
-+#define SR_EPCR 0x0B
-+#define EPCR_ERRE (1 << 0)
-+#define EPCR_ERPRW (1 << 1)
-+#define EPCR_ERPRR (1 << 2)
-+#define EPCR_EPOS (1 << 3)
-+#define EPCR_WEP (1 << 4)
-+/* Eeprom & Phy Address Reg */
-+#define SR_EPAR 0x0C
-+#define EPAR_EROA (0x3F << 0)
-+#define EPAR_PHY_ADR_MASK (0x03 << 6)
-+#define EPAR_PHY_ADR (0x01 << 6)
-+/* Eeprom & Phy Data Reg */
-+#define SR_EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */
-+/* Wakeup Control Reg */
-+#define SR_WCR 0x0F
-+#define WCR_MAGICST (1 << 0)
-+#define WCR_LINKST (1 << 2)
-+#define WCR_MAGICEN (1 << 3)
-+#define WCR_LINKEN (1 << 5)
-+/* Physical Address Reg */
-+#define SR_PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */
-+/* Multicast Address Reg */
-+#define SR_MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */
-+/* 0x1e unused */
-+/* Phy Reset Reg */
-+#define SR_PRR 0x1F
-+#define PRR_PHY_RST (1 << 0)
-+/* Tx sdram Write Pointer Address Low */
-+#define SR_TWPAL 0x20
-+/* Tx sdram Write Pointer Address High */
-+#define SR_TWPAH 0x21
-+/* Tx sdram Read Pointer Address Low */
-+#define SR_TRPAL 0x22
-+/* Tx sdram Read Pointer Address High */
-+#define SR_TRPAH 0x23
-+/* Rx sdram Write Pointer Address Low */
-+#define SR_RWPAL 0x24
-+/* Rx sdram Write Pointer Address High */
-+#define SR_RWPAH 0x25
-+/* Rx sdram Read Pointer Address Low */
-+#define SR_RRPAL 0x26
-+/* Rx sdram Read Pointer Address High */
-+#define SR_RRPAH 0x27
-+/* Vendor ID register */
-+#define SR_VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */
-+/* Product ID register */
-+#define SR_PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */
-+/* CHIP Revision register */
-+#define SR_CHIPR 0x2C
-+/* 0x2D --> 0xEF unused */
-+/* USB Device Address */
-+#define SR_USBDA 0xF0
-+#define USBDA_USBFA (0x7F << 0)
-+/* RX packet Counter Reg */
-+#define SR_RXC 0xF1
-+/* Tx packet Counter & USB Status Reg */
-+#define SR_TXC_USBS 0xF2
-+#define TXC_USBS_TXC0 (1 << 0)
-+#define TXC_USBS_TXC1 (1 << 1)
-+#define TXC_USBS_TXC2 (1 << 2)
-+#define TXC_USBS_EP1RDY (1 << 5)
-+#define TXC_USBS_SUSFLAG (1 << 6)
-+#define TXC_USBS_RXFAULT (1 << 7)
-+/* USB Control register */
-+#define SR_USBC 0xF4
-+#define USBC_EP3NAK (1 << 4)
-+#define USBC_EP3ACK (1 << 5)
-+
-+/* Register access commands and flags */
-+#define SR_RD_REGS 0x00
-+#define SR_WR_REGS 0x01
-+#define SR_WR_REG 0x03
-+#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
-+#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
-+
-+/* parameters */
-+#define SR_SHARE_TIMEOUT 1000
-+#define SR_EEPROM_LEN 256
-+#define SR_MCAST_SIZE 8
-+#define SR_MCAST_ADDR_FLAG 0x80
-+#define SR_MCAST_MAX 64
-+#define SR_TX_OVERHEAD 2 /* 2bytes header */
-+#define SR_RX_OVERHEAD 7 /* 3bytes header + 4crc tail */
-+
-+#endif /* _SR9700_H */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/sr9800.c backports-4.2.6-1/drivers/net/usb/sr9800.c
---- backports-4.2.6-1.org/drivers/net/usb/sr9800.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/sr9800.c 2016-06-28 14:35:18.015307217 +0200
-@@ -0,0 +1,875 @@
-+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
-+ *
-+ * Author : Liu Junliang <liujunliang_ljl@163.com>
-+ *
-+ * Based on asix_common.c, asix_devices.c
-+ *
-+ * This file is licensed under the terms of the GNU General Public License
-+ * version 2. This program is licensed "as is" without any warranty of any
-+ * kind, whether express or implied.*
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kmod.h>
-+#include <linux/init.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/usb.h>
-+#include <linux/crc32.h>
-+#include <linux/usb/usbnet.h>
-+#include <linux/slab.h>
-+#include <linux/if_vlan.h>
-+
-+#include "sr9800.h"
-+
-+static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ int err;
-+
-+ err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index,
-+ data, size);
-+ if ((err != size) && (err >= 0))
-+ err = -EINVAL;
-+
-+ return err;
-+}
-+
-+static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ int err;
-+
-+ err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index,
-+ data, size);
-+ if ((err != size) && (err >= 0))
-+ err = -EINVAL;
-+
-+ return err;
-+}
-+
-+static void
-+sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
-+ u16 size, void *data)
-+{
-+ usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data,
-+ size);
-+}
-+
-+static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
-+{
-+ int offset = 0;
-+
-+ /* This check is no longer done by usbnet */
-+ if (skb->len < dev->net->hard_header_len)
-+ return 0;
-+
-+ while (offset + sizeof(u32) < skb->len) {
-+ struct sk_buff *sr_skb;
-+ u16 size;
-+ u32 header = get_unaligned_le32(skb->data + offset);
-+
-+ offset += sizeof(u32);
-+ /* get the packet length */
-+ size = (u16) (header & 0x7ff);
-+ if (size != ((~header >> 16) & 0x07ff)) {
-+ netdev_err(dev->net, "%s : Bad Header Length\n",
-+ __func__);
-+ return 0;
-+ }
-+
-+ if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
-+ (size + offset > skb->len)) {
-+ netdev_err(dev->net, "%s : Bad RX Length %d\n",
-+ __func__, size);
-+ return 0;
-+ }
-+ sr_skb = netdev_alloc_skb_ip_align(dev->net, size);
-+ if (!sr_skb)
-+ return 0;
-+
-+ skb_put(sr_skb, size);
-+ memcpy(sr_skb->data, skb->data + offset, size);
-+ usbnet_skb_return(dev, sr_skb);
-+
-+ offset += (size + 1) & 0xfffe;
-+ }
-+
-+ if (skb->len != offset) {
-+ netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__,
-+ skb->len);
-+ return 0;
-+ }
-+
-+ return 1;
-+}
-+
-+static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
-+ gfp_t flags)
-+{
-+ int headroom = skb_headroom(skb);
-+ int tailroom = skb_tailroom(skb);
-+ u32 padbytes = 0xffff0000;
-+ u32 packet_len;
-+ int padlen;
-+
-+ padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4;
-+
-+ if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) {
-+ if ((headroom < 4) || (tailroom < padlen)) {
-+ skb->data = memmove(skb->head + 4, skb->data,
-+ skb->len);
-+ skb_set_tail_pointer(skb, skb->len);
-+ }
-+ } else {
-+ struct sk_buff *skb2;
-+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (!skb)
-+ return NULL;
-+ }
-+
-+ skb_push(skb, 4);
-+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
-+ cpu_to_le32s(&packet_len);
-+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
-+
-+ if (padlen) {
-+ cpu_to_le32s(&padbytes);
-+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
-+ skb_put(skb, sizeof(padbytes));
-+ }
-+
-+ usbnet_set_skb_tx_stats(skb, 1, 0);
-+ return skb;
-+}
-+
-+static void sr_status(struct usbnet *dev, struct urb *urb)
-+{
-+ struct sr9800_int_data *event;
-+ int link;
-+
-+ if (urb->actual_length < 8)
-+ return;
-+
-+ event = urb->transfer_buffer;
-+ link = event->link & 0x01;
-+ if (netif_carrier_ok(dev->net) != link) {
-+ usbnet_link_change(dev, link, 1);
-+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
-+ }
-+
-+ return;
-+}
-+
-+static inline int sr_set_sw_mii(struct usbnet *dev)
-+{
-+ int ret;
-+
-+ ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to enable software MII access\n");
-+ return ret;
-+}
-+
-+static inline int sr_set_hw_mii(struct usbnet *dev)
-+{
-+ int ret;
-+
-+ ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to enable hardware MII access\n");
-+ return ret;
-+}
-+
-+static inline int sr_get_phy_addr(struct usbnet *dev)
-+{
-+ u8 buf[2];
-+ int ret;
-+
-+ ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n",
-+ __func__, ret);
-+ goto out;
-+ }
-+ netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__,
-+ *((__le16 *)buf));
-+
-+ ret = buf[1];
-+
-+out:
-+ return ret;
-+}
-+
-+static int sr_sw_reset(struct usbnet *dev, u8 flags)
-+{
-+ int ret;
-+
-+ ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to send software reset:%02x\n",
-+ ret);
-+
-+ return ret;
-+}
-+
-+static u16 sr_read_rx_ctl(struct usbnet *dev)
-+{
-+ __le16 v;
-+ int ret;
-+
-+ ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Error reading RX_CTL register:%02x\n",
-+ ret);
-+ goto out;
-+ }
-+
-+ ret = le16_to_cpu(v);
-+out:
-+ return ret;
-+}
-+
-+static int sr_write_rx_ctl(struct usbnet *dev, u16 mode)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
-+ ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net,
-+ "Failed to write RX_CTL mode to 0x%04x:%02x\n",
-+ mode, ret);
-+
-+ return ret;
-+}
-+
-+static u16 sr_read_medium_status(struct usbnet *dev)
-+{
-+ __le16 v;
-+ int ret;
-+
-+ ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
-+ if (ret < 0) {
-+ netdev_err(dev->net,
-+ "Error reading Medium Status register:%02x\n", ret);
-+ return ret; /* TODO: callers not checking for error ret */
-+ }
-+
-+ return le16_to_cpu(v);
-+}
-+
-+static int sr_write_medium_mode(struct usbnet *dev, u16 mode)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
-+ ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net,
-+ "Failed to write Medium Mode mode to 0x%04x:%02x\n",
-+ mode, ret);
-+ return ret;
-+}
-+
-+static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep)
-+{
-+ int ret;
-+
-+ netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value);
-+ ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL);
-+ if (ret < 0)
-+ netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n",
-+ value, ret);
-+ if (sleep)
-+ msleep(sleep);
-+
-+ return ret;
-+}
-+
-+/* SR9800 have a 16-bit RX_CTL value */
-+static void sr_set_multicast(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+ u16 rx_ctl = SR_DEFAULT_RX_CTL;
-+
-+ if (net->flags & IFF_PROMISC) {
-+ rx_ctl |= SR_RX_CTL_PRO;
-+ } else if (net->flags & IFF_ALLMULTI ||
-+ netdev_mc_count(net) > SR_MAX_MCAST) {
-+ rx_ctl |= SR_RX_CTL_AMALL;
-+ } else if (netdev_mc_empty(net)) {
-+ /* just broadcast and directed */
-+ } else {
-+ /* We use the 20 byte dev->data
-+ * for our 8 byte filter buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later
-+ */
-+ struct netdev_hw_addr *ha;
-+ u32 crc_bits;
-+
-+ memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE);
-+
-+ /* Build the multicast hash filter. */
-+ netdev_for_each_mc_addr(ha, net) {
-+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
-+ data->multi_filter[crc_bits >> 3] |=
-+ 1 << (crc_bits & 7);
-+ }
-+
-+ sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0,
-+ SR_MCAST_FILTER_SIZE, data->multi_filter);
-+
-+ rx_ctl |= SR_RX_CTL_AM;
-+ }
-+
-+ sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
-+}
-+
-+static int sr_mdio_read(struct net_device *net, int phy_id, int loc)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ __le16 res;
-+
-+ mutex_lock(&dev->phy_mutex);
-+ sr_set_sw_mii(dev);
-+ sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res);
-+ sr_set_hw_mii(dev);
-+ mutex_unlock(&dev->phy_mutex);
-+
-+ netdev_dbg(dev->net,
-+ "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__,
-+ phy_id, loc, le16_to_cpu(res));
-+
-+ return le16_to_cpu(res);
-+}
-+
-+static void
-+sr_mdio_write(struct net_device *net, int phy_id, int loc, int val)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ __le16 res = cpu_to_le16(val);
-+
-+ netdev_dbg(dev->net,
-+ "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__,
-+ phy_id, loc, val);
-+ mutex_lock(&dev->phy_mutex);
-+ sr_set_sw_mii(dev);
-+ sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
-+ sr_set_hw_mii(dev);
-+ mutex_unlock(&dev->phy_mutex);
-+}
-+
-+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
-+static u32 sr_get_phyid(struct usbnet *dev)
-+{
-+ int phy_reg;
-+ u32 phy_id;
-+ int i;
-+
-+ /* Poll for the rare case the FW or phy isn't ready yet. */
-+ for (i = 0; i < 100; i++) {
-+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
-+ if (phy_reg != 0 && phy_reg != 0xFFFF)
-+ break;
-+ mdelay(1);
-+ }
-+
-+ if (phy_reg <= 0 || phy_reg == 0xFFFF)
-+ return 0;
-+
-+ phy_id = (phy_reg & 0xffff) << 16;
-+
-+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
-+ if (phy_reg < 0)
-+ return 0;
-+
-+ phy_id |= (phy_reg & 0xffff);
-+
-+ return phy_id;
-+}
-+
-+static void
-+sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt;
-+
-+ if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
-+ wolinfo->supported = 0;
-+ wolinfo->wolopts = 0;
-+ return;
-+ }
-+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
-+ wolinfo->wolopts = 0;
-+ if (opt & SR_MONITOR_LINK)
-+ wolinfo->wolopts |= WAKE_PHY;
-+ if (opt & SR_MONITOR_MAGIC)
-+ wolinfo->wolopts |= WAKE_MAGIC;
-+}
-+
-+static int
-+sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ u8 opt = 0;
-+
-+ if (wolinfo->wolopts & WAKE_PHY)
-+ opt |= SR_MONITOR_LINK;
-+ if (wolinfo->wolopts & WAKE_MAGIC)
-+ opt |= SR_MONITOR_MAGIC;
-+
-+ if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE,
-+ opt, 0, 0, NULL) < 0)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static int sr_get_eeprom_len(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+
-+ return data->eeprom_len;
-+}
-+
-+static int sr_get_eeprom(struct net_device *net,
-+ struct ethtool_eeprom *eeprom, u8 *data)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ __le16 *ebuf = (__le16 *)data;
-+ int ret;
-+ int i;
-+
-+ /* Crude hack to ensure that we don't overwrite memory
-+ * if an odd length is supplied
-+ */
-+ if (eeprom->len % 2)
-+ return -EINVAL;
-+
-+ eeprom->magic = SR_EEPROM_MAGIC;
-+
-+ /* sr9800 returns 2 bytes from eeprom on read */
-+ for (i = 0; i < eeprom->len / 2; i++) {
-+ ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i,
-+ 0, 2, &ebuf[i]);
-+ if (ret < 0)
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static void sr_get_drvinfo(struct net_device *net,
-+ struct ethtool_drvinfo *info)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+
-+ /* Inherit standard device info */
-+ usbnet_get_drvinfo(net, info);
-+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver));
-+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
-+ info->eedump_len = data->eeprom_len;
-+}
-+
-+static u32 sr_get_link(struct net_device *net)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return mii_link_ok(&dev->mii);
-+}
-+
-+static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+
-+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
-+}
-+
-+static int sr_set_mac_address(struct net_device *net, void *p)
-+{
-+ struct usbnet *dev = netdev_priv(net);
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+ struct sockaddr *addr = p;
-+
-+ if (netif_running(net))
-+ return -EBUSY;
-+ if (!is_valid_ether_addr(addr->sa_data))
-+ return -EADDRNOTAVAIL;
-+
-+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
-+
-+ /* We use the 20 byte dev->data
-+ * for our 6 byte mac buffer
-+ * to avoid allocating memory that
-+ * is tricky to free later
-+ */
-+ memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
-+ sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+
-+ return 0;
-+}
-+
-+static const struct ethtool_ops sr9800_ethtool_ops = {
-+ .get_drvinfo = sr_get_drvinfo,
-+ .get_link = sr_get_link,
-+ .get_msglevel = usbnet_get_msglevel,
-+ .set_msglevel = usbnet_set_msglevel,
-+ .get_wol = sr_get_wol,
-+ .set_wol = sr_set_wol,
-+ .get_eeprom_len = sr_get_eeprom_len,
-+ .get_eeprom = sr_get_eeprom,
-+ .get_settings = usbnet_get_settings,
-+ .set_settings = usbnet_set_settings,
-+ .nway_reset = usbnet_nway_reset,
-+};
-+
-+static int sr9800_link_reset(struct usbnet *dev)
-+{
-+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
-+ u16 mode;
-+
-+ mii_check_media(&dev->mii, 1, 1);
-+ mii_ethtool_gset(&dev->mii, &ecmd);
-+ mode = SR9800_MEDIUM_DEFAULT;
-+
-+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
-+ mode &= ~SR_MEDIUM_PS;
-+
-+ if (ecmd.duplex != DUPLEX_FULL)
-+ mode &= ~SR_MEDIUM_FD;
-+
-+ netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n",
-+ __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
-+
-+ sr_write_medium_mode(dev, mode);
-+
-+ return 0;
-+}
-+
-+
-+static int sr9800_set_default_mode(struct usbnet *dev)
-+{
-+ u16 rx_ctl;
-+ int ret;
-+
-+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
-+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
-+ ADVERTISE_ALL | ADVERTISE_CSMA);
-+ mii_nway_restart(&dev->mii);
-+
-+ ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT);
-+ if (ret < 0)
-+ goto out;
-+
-+ ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012,
-+ SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT,
-+ SR9800_IPG2_DEFAULT, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
-+ goto out;
-+ }
-+
-+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
-+ ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = sr_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ rx_ctl = sr_read_medium_status(dev);
-+ netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n",
-+ rx_ctl);
-+
-+ return 0;
-+out:
-+ return ret;
-+}
-+
-+static int sr9800_reset(struct usbnet *dev)
-+{
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+ int ret, embd_phy;
-+ u16 rx_ctl;
-+
-+ ret = sr_write_gpio(dev,
-+ SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5);
-+ if (ret < 0)
-+ goto out;
-+
-+ embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
-+
-+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
-+ goto out;
-+ }
-+
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ if (embd_phy) {
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
-+ if (ret < 0)
-+ goto out;
-+ } else {
-+ ret = sr_sw_reset(dev, SR_SWRESET_PRTE);
-+ if (ret < 0)
-+ goto out;
-+ }
-+
-+ msleep(150);
-+ rx_ctl = sr_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
-+ ret = sr_write_rx_ctl(dev, 0x0000);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = sr_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
-+
-+ ret = sr_sw_reset(dev, SR_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL);
-+ if (ret < 0)
-+ goto out;
-+
-+ msleep(150);
-+
-+ ret = sr9800_set_default_mode(dev);
-+ if (ret < 0)
-+ goto out;
-+
-+ /* Rewrite MAC address */
-+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
-+ ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
-+ data->mac_addr);
-+ if (ret < 0)
-+ goto out;
-+
-+ return 0;
-+
-+out:
-+ return ret;
-+}
-+
-+static const struct net_device_ops sr9800_netdev_ops = {
-+ .ndo_open = usbnet_open,
-+ .ndo_stop = usbnet_stop,
-+ .ndo_start_xmit = usbnet_start_xmit,
-+ .ndo_tx_timeout = usbnet_tx_timeout,
-+ .ndo_change_mtu = usbnet_change_mtu,
-+ .ndo_set_mac_address = sr_set_mac_address,
-+ .ndo_validate_addr = eth_validate_addr,
-+ .ndo_do_ioctl = sr_ioctl,
-+ .ndo_set_rx_mode = sr_set_multicast,
-+};
-+
-+static int sr9800_phy_powerup(struct usbnet *dev)
-+{
-+ int ret;
-+
-+ /* set the embedded Ethernet PHY in power-down state */
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to power down PHY : %d\n", ret);
-+ return ret;
-+ }
-+ msleep(20);
-+
-+ /* set the embedded Ethernet PHY in power-up state */
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
-+ return ret;
-+ }
-+ msleep(600);
-+
-+ /* set the embedded Ethernet PHY in reset state */
-+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to power up PHY: %d\n", ret);
-+ return ret;
-+ }
-+ msleep(20);
-+
-+ /* set the embedded Ethernet PHY in power-up state */
-+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ struct sr_data *data = (struct sr_data *)&dev->data;
-+ u16 led01_mux, led23_mux;
-+ int ret, embd_phy;
-+ u32 phyid;
-+ u16 rx_ctl;
-+
-+ data->eeprom_len = SR9800_EEPROM_LEN;
-+
-+ usbnet_get_endpoints(dev, intf);
-+
-+ /* LED Setting Rule :
-+ * AABB:CCDD
-+ * AA : MFA0(LED0)
-+ * BB : MFA1(LED1)
-+ * CC : MFA2(LED2), Reserved for SR9800
-+ * DD : MFA3(LED3), Reserved for SR9800
-+ */
-+ led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK;
-+ led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE;
-+ ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "set LINK LED failed : %d\n", ret);
-+ goto out;
-+ }
-+
-+ /* Get the MAC address */
-+ ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN,
-+ dev->net->dev_addr);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
-+ return ret;
-+ }
-+ netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr);
-+
-+ /* Initialize MII structure */
-+ dev->mii.dev = dev->net;
-+ dev->mii.mdio_read = sr_mdio_read;
-+ dev->mii.mdio_write = sr_mdio_write;
-+ dev->mii.phy_id_mask = 0x1f;
-+ dev->mii.reg_num_mask = 0x1f;
-+ dev->mii.phy_id = sr_get_phy_addr(dev);
-+
-+ dev->net->netdev_ops = &sr9800_netdev_ops;
-+ dev->net->ethtool_ops = &sr9800_ethtool_ops;
-+
-+ embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
-+ /* Reset the PHY to normal operation mode */
-+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
-+ if (ret < 0) {
-+ netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* Init PHY routine */
-+ ret = sr9800_phy_powerup(dev);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = sr_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
-+ ret = sr_write_rx_ctl(dev, 0x0000);
-+ if (ret < 0)
-+ goto out;
-+
-+ rx_ctl = sr_read_rx_ctl(dev);
-+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
-+
-+ /* Read PHYID register *AFTER* the PHY was reset properly */
-+ phyid = sr_get_phyid(dev);
-+ netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
-+
-+ /* medium mode setting */
-+ ret = sr9800_set_default_mode(dev);
-+ if (ret < 0)
-+ goto out;
-+
-+ if (dev->udev->speed == USB_SPEED_HIGH) {
-+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt,
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold,
-+ 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
-+ goto out;
-+ }
-+ dev->rx_urb_size =
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size;
-+ } else {
-+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt,
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold,
-+ 0, NULL);
-+ if (ret < 0) {
-+ netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
-+ goto out;
-+ }
-+ dev->rx_urb_size =
-+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size;
-+ }
-+ netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__,
-+ dev->rx_urb_size);
-+ return 0;
-+
-+out:
-+ return ret;
-+}
-+
-+static const struct driver_info sr9800_driver_info = {
-+ .description = "CoreChip SR9800 USB 2.0 Ethernet",
-+ .bind = sr9800_bind,
-+ .status = sr_status,
-+ .link_reset = sr9800_link_reset,
-+ .reset = sr9800_reset,
-+ .flags = DRIVER_FLAG,
-+ .rx_fixup = sr_rx_fixup,
-+ .tx_fixup = sr_tx_fixup,
-+};
-+
-+static const struct usb_device_id products[] = {
-+ {
-+ USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */
-+ .driver_info = (unsigned long) &sr9800_driver_info,
-+ },
-+ {}, /* END */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver sr_driver = {
-+ .name = DRIVER_NAME,
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disconnect = usbnet_disconnect,
-+ .supports_autosuspend = 1,
-+};
-+
-+module_usb_driver(sr_driver);
-+
-+MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com");
-+MODULE_VERSION(DRIVER_VERSION);
-+MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com");
-+MODULE_LICENSE("GPL");
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/sr9800.h backports-4.2.6-1/drivers/net/usb/sr9800.h
---- backports-4.2.6-1.org/drivers/net/usb/sr9800.h 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/sr9800.h 2016-06-28 14:35:18.015307217 +0200
-@@ -0,0 +1,202 @@
-+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
-+ *
-+ * Author : Liu Junliang <liujunliang_ljl@163.com>
-+ *
-+ * This file is licensed under the terms of the GNU General Public License
-+ * version 2. This program is licensed "as is" without any warranty of any
-+ * kind, whether express or implied.
-+ */
-+
-+#ifndef _SR9800_H
-+#define _SR9800_H
-+
-+/* SR9800 spec. command table on Linux Platform */
-+
-+/* command : Software Station Management Control Reg */
-+#define SR_CMD_SET_SW_MII 0x06
-+/* command : PHY Read Reg */
-+#define SR_CMD_READ_MII_REG 0x07
-+/* command : PHY Write Reg */
-+#define SR_CMD_WRITE_MII_REG 0x08
-+/* command : Hardware Station Management Control Reg */
-+#define SR_CMD_SET_HW_MII 0x0a
-+/* command : SROM Read Reg */
-+#define SR_CMD_READ_EEPROM 0x0b
-+/* command : SROM Write Reg */
-+#define SR_CMD_WRITE_EEPROM 0x0c
-+/* command : SROM Write Enable Reg */
-+#define SR_CMD_WRITE_ENABLE 0x0d
-+/* command : SROM Write Disable Reg */
-+#define SR_CMD_WRITE_DISABLE 0x0e
-+/* command : RX Control Read Reg */
-+#define SR_CMD_READ_RX_CTL 0x0f
-+#define SR_RX_CTL_PRO (1 << 0)
-+#define SR_RX_CTL_AMALL (1 << 1)
-+#define SR_RX_CTL_SEP (1 << 2)
-+#define SR_RX_CTL_AB (1 << 3)
-+#define SR_RX_CTL_AM (1 << 4)
-+#define SR_RX_CTL_AP (1 << 5)
-+#define SR_RX_CTL_ARP (1 << 6)
-+#define SR_RX_CTL_SO (1 << 7)
-+#define SR_RX_CTL_RH1M (1 << 8)
-+#define SR_RX_CTL_RH2M (1 << 9)
-+#define SR_RX_CTL_RH3M (1 << 10)
-+/* command : RX Control Write Reg */
-+#define SR_CMD_WRITE_RX_CTL 0x10
-+/* command : IPG0/IPG1/IPG2 Control Read Reg */
-+#define SR_CMD_READ_IPG012 0x11
-+/* command : IPG0/IPG1/IPG2 Control Write Reg */
-+#define SR_CMD_WRITE_IPG012 0x12
-+/* command : Node ID Read Reg */
-+#define SR_CMD_READ_NODE_ID 0x13
-+/* command : Node ID Write Reg */
-+#define SR_CMD_WRITE_NODE_ID 0x14
-+/* command : Multicast Filter Array Read Reg */
-+#define SR_CMD_READ_MULTI_FILTER 0x15
-+/* command : Multicast Filter Array Write Reg */
-+#define SR_CMD_WRITE_MULTI_FILTER 0x16
-+/* command : Eth/HomePNA PHY Address Reg */
-+#define SR_CMD_READ_PHY_ID 0x19
-+/* command : Medium Status Read Reg */
-+#define SR_CMD_READ_MEDIUM_STATUS 0x1a
-+#define SR_MONITOR_LINK (1 << 1)
-+#define SR_MONITOR_MAGIC (1 << 2)
-+#define SR_MONITOR_HSFS (1 << 4)
-+/* command : Medium Status Write Reg */
-+#define SR_CMD_WRITE_MEDIUM_MODE 0x1b
-+#define SR_MEDIUM_GM (1 << 0)
-+#define SR_MEDIUM_FD (1 << 1)
-+#define SR_MEDIUM_AC (1 << 2)
-+#define SR_MEDIUM_ENCK (1 << 3)
-+#define SR_MEDIUM_RFC (1 << 4)
-+#define SR_MEDIUM_TFC (1 << 5)
-+#define SR_MEDIUM_JFE (1 << 6)
-+#define SR_MEDIUM_PF (1 << 7)
-+#define SR_MEDIUM_RE (1 << 8)
-+#define SR_MEDIUM_PS (1 << 9)
-+#define SR_MEDIUM_RSV (1 << 10)
-+#define SR_MEDIUM_SBP (1 << 11)
-+#define SR_MEDIUM_SM (1 << 12)
-+/* command : Monitor Mode Status Read Reg */
-+#define SR_CMD_READ_MONITOR_MODE 0x1c
-+/* command : Monitor Mode Status Write Reg */
-+#define SR_CMD_WRITE_MONITOR_MODE 0x1d
-+/* command : GPIO Status Read Reg */
-+#define SR_CMD_READ_GPIOS 0x1e
-+#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */
-+#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */
-+#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */
-+#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */
-+#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */
-+#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */
-+#define SR_GPIO_RESERVED (1 << 6) /* Reserved */
-+#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */
-+/* command : GPIO Status Write Reg */
-+#define SR_CMD_WRITE_GPIOS 0x1f
-+/* command : Eth PHY Power and Reset Control Reg */
-+#define SR_CMD_SW_RESET 0x20
-+#define SR_SWRESET_CLEAR 0x00
-+#define SR_SWRESET_RR (1 << 0)
-+#define SR_SWRESET_RT (1 << 1)
-+#define SR_SWRESET_PRTE (1 << 2)
-+#define SR_SWRESET_PRL (1 << 3)
-+#define SR_SWRESET_BZ (1 << 4)
-+#define SR_SWRESET_IPRL (1 << 5)
-+#define SR_SWRESET_IPPD (1 << 6)
-+/* command : Software Interface Selection Status Read Reg */
-+#define SR_CMD_SW_PHY_STATUS 0x21
-+/* command : Software Interface Selection Status Write Reg */
-+#define SR_CMD_SW_PHY_SELECT 0x22
-+/* command : BULK in Buffer Size Reg */
-+#define SR_CMD_BULKIN_SIZE 0x2A
-+/* command : LED_MUX Control Reg */
-+#define SR_CMD_LED_MUX 0x70
-+#define SR_LED_MUX_TX_ACTIVE (1 << 0)
-+#define SR_LED_MUX_RX_ACTIVE (1 << 1)
-+#define SR_LED_MUX_COLLISION (1 << 2)
-+#define SR_LED_MUX_DUP_COL (1 << 3)
-+#define SR_LED_MUX_DUP (1 << 4)
-+#define SR_LED_MUX_SPEED (1 << 5)
-+#define SR_LED_MUX_LINK_ACTIVE (1 << 6)
-+#define SR_LED_MUX_LINK (1 << 7)
-+
-+/* Register Access Flags */
-+#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
-+#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
-+
-+/* Multicast Filter Array size & Max Number */
-+#define SR_MCAST_FILTER_SIZE 8
-+#define SR_MAX_MCAST 64
-+
-+/* IPG0/1/2 Default Value */
-+#define SR9800_IPG0_DEFAULT 0x15
-+#define SR9800_IPG1_DEFAULT 0x0c
-+#define SR9800_IPG2_DEFAULT 0x12
-+
-+/* Medium Status Default Mode */
-+#define SR9800_MEDIUM_DEFAULT \
-+ (SR_MEDIUM_FD | SR_MEDIUM_RFC | \
-+ SR_MEDIUM_TFC | SR_MEDIUM_PS | \
-+ SR_MEDIUM_AC | SR_MEDIUM_RE)
-+
-+/* RX Control Default Setting */
-+#define SR_DEFAULT_RX_CTL \
-+ (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M)
-+
-+/* EEPROM Magic Number & EEPROM Size */
-+#define SR_EEPROM_MAGIC 0xdeadbeef
-+#define SR9800_EEPROM_LEN 0xff
-+
-+/* SR9800 Driver Version and Driver Name */
-+#define DRIVER_VERSION "11-Nov-2013"
-+#define DRIVER_NAME "CoreChips"
-+#define DRIVER_FLAG \
-+ (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET)
-+
-+/* SR9800 BULKIN Buffer Size */
-+#define SR9800_MAX_BULKIN_2K 0
-+#define SR9800_MAX_BULKIN_4K 1
-+#define SR9800_MAX_BULKIN_6K 2
-+#define SR9800_MAX_BULKIN_8K 3
-+#define SR9800_MAX_BULKIN_16K 4
-+#define SR9800_MAX_BULKIN_20K 5
-+#define SR9800_MAX_BULKIN_24K 6
-+#define SR9800_MAX_BULKIN_32K 7
-+
-+struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = {
-+ /* 2k */
-+ {2048, 0x8000, 0x8001},
-+ /* 4k */
-+ {4096, 0x8100, 0x8147},
-+ /* 6k */
-+ {6144, 0x8200, 0x81EB},
-+ /* 8k */
-+ {8192, 0x8300, 0x83D7},
-+ /* 16 */
-+ {16384, 0x8400, 0x851E},
-+ /* 20k */
-+ {20480, 0x8500, 0x8666},
-+ /* 24k */
-+ {24576, 0x8600, 0x87AE},
-+ /* 32k */
-+ {32768, 0x8700, 0x8A3D},
-+};
-+
-+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
-+struct sr_data {
-+ u8 multi_filter[SR_MCAST_FILTER_SIZE];
-+ u8 mac_addr[ETH_ALEN];
-+ u8 phymode;
-+ u8 ledmode;
-+ u8 eeprom_len;
-+};
-+
-+struct sr9800_int_data {
-+ __le16 res1;
-+ u8 link;
-+ __le16 res2;
-+ u8 status;
-+ __le16 res3;
-+} __packed;
-+
-+#endif /* _SR9800_H */
-diff -Naur backports-4.2.6-1.org/drivers/net/usb/zaurus.c backports-4.2.6-1/drivers/net/usb/zaurus.c
---- backports-4.2.6-1.org/drivers/net/usb/zaurus.c 1970-01-01 01:00:00.000000000 +0100
-+++ backports-4.2.6-1/drivers/net/usb/zaurus.c 2016-06-28 14:35:18.015307217 +0200
-@@ -0,0 +1,385 @@
-+/*
-+ * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
-+ * Copyright (C) 2002-2005 by David Brownell
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+// #define DEBUG // error path messages, extra info
-+// #define VERBOSE // more; success messages
-+
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/ethtool.h>
-+#include <linux/workqueue.h>
-+#include <linux/mii.h>
-+#include <linux/crc32.h>
-+#include <linux/usb.h>
-+#include <linux/usb/cdc.h>
-+#include <linux/usb/usbnet.h>
-+
-+
-+/*
-+ * All known Zaurii lie about their standards conformance. At least
-+ * the earliest SA-1100 models lie by saying they support CDC Ethernet.
-+ * Some later models (especially PXA-25x and PXA-27x based ones) lie
-+ * and say they support CDC MDLM (for access to cell phone modems).
-+ *
-+ * There are non-Zaurus products that use these same protocols too.
-+ *
-+ * The annoying thing is that at the same time Sharp was developing
-+ * that annoying standards-breaking software, the Linux community had
-+ * a simple "CDC Subset" working reliably on the same SA-1100 hardware.
-+ * That is, the same functionality but not violating standards.
-+ *
-+ * The CDC Ethernet nonconformance points are troublesome to hosts
-+ * with a true CDC Ethernet implementation:
-+ * - Framing appends a CRC, which the spec says drivers "must not" do;
-+ * - Transfers data in altsetting zero, instead of altsetting 1;
-+ * - All these peripherals use the same ethernet address.
-+ *
-+ * The CDC MDLM nonconformance is less immediately troublesome, since all
-+ * MDLM implementations are quasi-proprietary anyway.
-+ */
-+
-+static struct sk_buff *
-+zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
-+{
-+ int padlen;
-+ struct sk_buff *skb2;
-+
-+ padlen = 2;
-+ if (!skb_cloned(skb)) {
-+ int tailroom = skb_tailroom(skb);
-+ if ((padlen + 4) <= tailroom)
-+ goto done;
-+ }
-+ skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags);
-+ dev_kfree_skb_any(skb);
-+ skb = skb2;
-+ if (skb) {
-+ u32 fcs;
-+done:
-+ fcs = crc32_le(~0, skb->data, skb->len);
-+ fcs = ~fcs;
-+
-+ *skb_put (skb, 1) = fcs & 0xff;
-+ *skb_put (skb, 1) = (fcs>> 8) & 0xff;
-+ *skb_put (skb, 1) = (fcs>>16) & 0xff;
-+ *skb_put (skb, 1) = (fcs>>24) & 0xff;
-+ }
-+ return skb;
-+}
-+
-+static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ /* Belcarra's funky framing has other options; mostly
-+ * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes.
-+ */
-+ dev->net->hard_header_len += 6;
-+ dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;
-+ return usbnet_generic_cdc_bind(dev, intf);
-+}
-+
-+/* PDA style devices are always connected if present */
-+static int always_connected (struct usbnet *dev)
-+{
-+ return 0;
-+}
-+
-+static const struct driver_info zaurus_sl5x00_info = {
-+ .description = "Sharp Zaurus SL-5x00",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
-+ .check_connect = always_connected,
-+ .bind = zaurus_bind,
-+ .unbind = usbnet_cdc_unbind,
-+ .tx_fixup = zaurus_tx_fixup,
-+};
-+#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info)
-+
-+static const struct driver_info zaurus_pxa_info = {
-+ .description = "Sharp Zaurus, PXA-2xx based",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
-+ .check_connect = always_connected,
-+ .bind = zaurus_bind,
-+ .unbind = usbnet_cdc_unbind,
-+ .tx_fixup = zaurus_tx_fixup,
-+};
-+#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info)
-+
-+static const struct driver_info olympus_mxl_info = {
-+ .description = "Olympus R1000",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
-+ .check_connect = always_connected,
-+ .bind = zaurus_bind,
-+ .unbind = usbnet_cdc_unbind,
-+ .tx_fixup = zaurus_tx_fixup,
-+};
-+#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info)
-+
-+
-+/* Some more recent products using Lineo/Belcarra code will wrongly claim
-+ * CDC MDLM conformance. They aren't conformant: data endpoints live
-+ * in the control interface, there's no data interface, and it's not used
-+ * to talk to a cell phone radio. But at least we can detect these two
-+ * pseudo-classes, rather than growing this product list with entries for
-+ * each new nonconformant product (sigh).
-+ */
-+static const u8 safe_guid[16] = {
-+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
-+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
-+};
-+static const u8 blan_guid[16] = {
-+ 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70,
-+ 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37,
-+};
-+
-+static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf)
-+{
-+ u8 *buf = intf->cur_altsetting->extra;
-+ int len = intf->cur_altsetting->extralen;
-+ struct usb_cdc_mdlm_desc *desc = NULL;
-+ struct usb_cdc_mdlm_detail_desc *detail = NULL;
-+
-+ while (len > 3) {
-+ if (buf [1] != USB_DT_CS_INTERFACE)
-+ goto next_desc;
-+
-+ /* use bDescriptorSubType, and just verify that we get a
-+ * "BLAN" (or "SAFE") descriptor.
-+ */
-+ switch (buf [2]) {
-+ case USB_CDC_MDLM_TYPE:
-+ if (desc) {
-+ dev_dbg(&intf->dev, "extra MDLM\n");
-+ goto bad_desc;
-+ }
-+ desc = (void *) buf;
-+ if (desc->bLength != sizeof *desc) {
-+ dev_dbg(&intf->dev, "MDLM len %u\n",
-+ desc->bLength);
-+ goto bad_desc;
-+ }
-+ /* expect bcdVersion 1.0, ignore */
-+ if (memcmp(&desc->bGUID, blan_guid, 16) &&
-+ memcmp(&desc->bGUID, safe_guid, 16)) {
-+ /* hey, this one might _really_ be MDLM! */
-+ dev_dbg(&intf->dev, "MDLM guid\n");
-+ goto bad_desc;
-+ }
-+ break;
-+ case USB_CDC_MDLM_DETAIL_TYPE:
-+ if (detail) {
-+ dev_dbg(&intf->dev, "extra MDLM detail\n");
-+ goto bad_desc;
-+ }
-+ detail = (void *) buf;
-+ switch (detail->bGuidDescriptorType) {
-+ case 0: /* "SAFE" */
-+ if (detail->bLength != (sizeof *detail + 2))
-+ goto bad_detail;
-+ break;
-+ case 1: /* "BLAN" */
-+ if (detail->bLength != (sizeof *detail + 3))
-+ goto bad_detail;
-+ break;
-+ default:
-+ goto bad_detail;
-+ }
-+
-+ /* assuming we either noticed BLAN already, or will
-+ * find it soon, there are some data bytes here:
-+ * - bmNetworkCapabilities (unused)
-+ * - bmDataCapabilities (bits, see below)
-+ * - bPad (ignored, for PADAFTER -- BLAN-only)
-+ * bits are:
-+ * - 0x01 -- Zaurus framing (add CRC)
-+ * - 0x02 -- PADBEFORE (CRC includes some padding)
-+ * - 0x04 -- PADAFTER (some padding after CRC)
-+ * - 0x08 -- "fermat" packet mangling (for hw bugs)
-+ * the PADBEFORE appears not to matter; we interop
-+ * with devices that use it and those that don't.
-+ */
-+ if ((detail->bDetailData[1] & ~0x02) != 0x01) {
-+ /* bmDataCapabilities == 0 would be fine too,
-+ * but framing is minidriver-coupled for now.
-+ */
-+bad_detail:
-+ dev_dbg(&intf->dev,
-+ "bad MDLM detail, %d %d %d\n",
-+ detail->bLength,
-+ detail->bDetailData[0],
-+ detail->bDetailData[2]);
-+ goto bad_desc;
-+ }
-+
-+ /* same extra framing as for non-BLAN mode */
-+ dev->net->hard_header_len += 6;
-+ dev->rx_urb_size = dev->net->hard_header_len
-+ + dev->net->mtu;
-+ break;
-+ }
-+next_desc:
-+ len -= buf [0]; /* bLength */
-+ buf += buf [0];
-+ }
-+
-+ if (!desc || !detail) {
-+ dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n",
-+ desc ? "" : "func ",
-+ detail ? "" : "detail ");
-+ goto bad_desc;
-+ }
-+
-+ /* There's probably a CDC Ethernet descriptor there, but we can't
-+ * rely on the Ethernet address it provides since not all vendors
-+ * bother to make it unique. Likewise there's no point in tracking
-+ * of the CDC event notifications.
-+ */
-+ return usbnet_get_endpoints(dev, intf);
-+
-+bad_desc:
-+ dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n");
-+ return -ENODEV;
-+}
-+
-+static const struct driver_info bogus_mdlm_info = {
-+ .description = "pseudo-MDLM (BLAN) device",
-+ .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z,
-+ .check_connect = always_connected,
-+ .tx_fixup = zaurus_tx_fixup,
-+ .bind = blan_mdlm_bind,
-+};
-+
-+static const struct usb_device_id products [] = {
-+#define ZAURUS_MASTER_INTERFACE \
-+ .bInterfaceClass = USB_CLASS_COMM, \
-+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \
-+ .bInterfaceProtocol = USB_CDC_PROTO_NONE
-+
-+/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */
-+{
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x8004,
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_STRONGARM_INFO,
-+},
-+
-+/* PXA-2xx based models are also lying-about-cdc. If you add any
-+ * more devices that claim to be CDC Ethernet, make sure they get
-+ * added to the blacklist in cdc_ether too.
-+ *
-+ * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries,
-+ * unlike the older ones with 2.4 "embedix" kernels.
-+ */
-+{
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x8005, /* A-300 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+}, {
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x8006, /* B-500/SL-5600 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+}, {
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x8007, /* C-700 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+}, {
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x9031, /* C-750 C-760 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+}, {
-+ /* C-750/C-760/C-860/SL-C3000 PDA in MDLM mode */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x04DD, 0x9031, USB_CLASS_COMM,
-+ USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-+ .driver_info = (unsigned long) &bogus_mdlm_info,
-+}, {
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ .idProduct = 0x9032, /* SL-6000 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+}, {
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x04DD,
-+ /* reported with some C860 units */
-+ .idProduct = 0x9050, /* C-860 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = ZAURUS_PXA_INFO,
-+},
-+{
-+ /* Motorola Rokr E6 */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM,
-+ USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-+ .driver_info = (unsigned long) &bogus_mdlm_info,
-+}, {
-+ /* Motorola MOTOMAGX phones */
-+ USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM,
-+ USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-+ .driver_info = (unsigned long) &bogus_mdlm_info,
-+},
-+
-+/* Olympus has some models with a Zaurus-compatible option.
-+ * R-1000 uses a FreeScale i.MXL cpu (ARMv4T)
-+ */
-+{
-+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
-+ | USB_DEVICE_ID_MATCH_DEVICE,
-+ .idVendor = 0x07B4,
-+ .idProduct = 0x0F02, /* R-1000 */
-+ ZAURUS_MASTER_INTERFACE,
-+ .driver_info = OLYMPUS_MXL_INFO,
-+},
-+
-+/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */
-+{
-+ USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM,
-+ USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-+ .driver_info = (unsigned long) &bogus_mdlm_info,
-+},
-+ { }, // END
-+};
-+MODULE_DEVICE_TABLE(usb, products);
-+
-+static struct usb_driver zaurus_driver = {
-+ .name = "zaurus",
-+ .id_table = products,
-+ .probe = usbnet_probe,
-+ .disconnect = usbnet_disconnect,
-+ .suspend = usbnet_suspend,
-+ .resume = usbnet_resume,
-+ .disable_hub_initiated_lpm = 1,
-+};
-+
-+module_usb_driver(zaurus_driver);
-+
-+MODULE_AUTHOR("Pavel Machek, David Brownell");
-+MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products");
-+MODULE_LICENSE("GPL");