aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/net')
-rw-r--r--drivers/usb/net/Kconfig20
-rw-r--r--drivers/usb/net/Makefile1
-rw-r--r--drivers/usb/net/asix.c24
-rw-r--r--drivers/usb/net/catc.c30
-rw-r--r--drivers/usb/net/cdc_subset.c21
-rw-r--r--drivers/usb/net/dm9601.c619
-rw-r--r--drivers/usb/net/gl620a.c2
-rw-r--r--drivers/usb/net/kaweth.c2
-rw-r--r--drivers/usb/net/net1080.c2
-rw-r--r--drivers/usb/net/pegasus.c14
-rw-r--r--drivers/usb/net/rndis_host.c114
-rw-r--r--drivers/usb/net/rtl8150.c1
-rw-r--r--drivers/usb/net/usbnet.c38
-rw-r--r--drivers/usb/net/usbnet.h1
14 files changed, 807 insertions, 82 deletions
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index a2b94ef512b..3de564b2314 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -84,6 +84,7 @@ config USB_PEGASUS
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select MII
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
Send me <petkan@users.sourceforge.net> any comments you may have.
@@ -98,7 +99,7 @@ config USB_USBNET_MII
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
- select MII if USBNET_MII != n
+ select MII if USB_USBNET_MII != n
---help---
This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core
@@ -185,6 +186,15 @@ config USB_NET_CDCETHER
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
+config USB_NET_DM9601
+ tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ select USB_USBNET_MII
+ help
+ This option adds support for Davicom DM9601 based USB 1.1
+ 10/100 Ethernet adapters.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
@@ -239,6 +249,7 @@ config USB_NET_RNDIS_HOST
config USB_NET_CDC_SUBSET
tristate "Simple USB Network Links (CDC Ethernet subset)"
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
@@ -298,6 +309,13 @@ config USB_EPSON2888
Choose this option to support the usb networking links used
by some sample firmware from Epson.
+config USB_KC2190
+ boolean "KT Technology KC2190 based cables (InstaNet)"
+ depends on USB_NET_CDC_SUBSET && EXPERIMENTAL
+ help
+  Choose this option if you're using a host-to-host cable
+  with one of these chips.
+
config USB_NET_ZAURUS
tristate "Sharp Zaurus (stock ROMs) and compatible"
depends on USB_USBNET
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 7b51964de17..595a539f838 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
+obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index bd357e178e5..d5ef97bc4d0 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -298,7 +298,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (ax_skb) {
ax_skb->len = size;
ax_skb->data = packet;
- ax_skb->tail = packet + size;
+ skb_set_tail_pointer(ax_skb, size);
usbnet_skb_return(dev, ax_skb);
} else {
return 0;
@@ -338,7 +338,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
&& ((headroom + tailroom) >= (4 + padlen))) {
if ((headroom < 4) || (tailroom < padlen)) {
skb->data = memmove(skb->head + 4, skb->data, skb->len);
- skb->tail = skb->data + skb->len;
+ skb_set_tail_pointer(skb, skb->len);
}
} else {
struct sk_buff *skb2;
@@ -351,10 +351,12 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
skb_push(skb, 4);
packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
- memcpy(skb->data, &packet_len, sizeof(packet_len));
+ cpu_to_le32s(&packet_len);
+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
if ((skb->len % 512) == 0) {
- memcpy( skb->tail, &padbytes, sizeof(padbytes));
+ cpu_to_le32s(&padbytes);
+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
skb_put(skb, sizeof(padbytes));
}
return skb;
@@ -1393,9 +1395,9 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
}, {
- // Billionton Systems, USB2AR
- USB_DEVICE (0x08dd, 0x90ff),
- .driver_info = (unsigned long) &ax8817x_info,
+ // Billionton Systems, USB2AR
+ USB_DEVICE (0x08dd, 0x90ff),
+ .driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
@@ -1421,9 +1423,13 @@ static const struct usb_device_id products [] = {
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,
+}, {
// ASIX AX88772 10/100
- USB_DEVICE (0x0b95, 0x7720),
- .driver_info = (unsigned long) &ax88772_info,
+ USB_DEVICE (0x0b95, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
}, {
// ASIX AX88178 10/100/1000
USB_DEVICE (0x0b95, 0x1780),
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
index 4852012735f..86e90c59d55 100644
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -255,7 +255,6 @@ static void catc_rx_done(struct urb *urb)
if (!(skb = dev_alloc_skb(pkt_len)))
return;
- skb->dev = catc->netdev;
eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0);
skb_put(skb, pkt_len);
@@ -356,7 +355,7 @@ resubmit:
* Transmit routines.
*/
-static void catc_tx_run(struct catc *catc)
+static int catc_tx_run(struct catc *catc)
{
int status;
@@ -374,12 +373,14 @@ static void catc_tx_run(struct catc *catc)
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;
if (urb->status == -ECONNRESET) {
dbg("Tx Reset.");
@@ -398,10 +399,13 @@ static void catc_tx_done(struct urb *urb)
spin_lock_irqsave(&catc->tx_lock, flags);
- if (catc->tx_ptr)
- catc_tx_run(catc);
- else
+ 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);
@@ -412,6 +416,7 @@ static int catc_hard_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);
@@ -419,11 +424,14 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
*((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len);
- memcpy(tx_buf + 2, skb->data, 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))
- catc_tx_run(catc);
+ 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))))
@@ -431,8 +439,10 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
spin_unlock_irqrestore(&catc->tx_lock, flags);
- catc->stats.tx_bytes += skb->len;
- catc->stats.tx_packets++;
+ if (r >= 0) {
+ catc->stats.tx_bytes += skb->len;
+ catc->stats.tx_packets++;
+ }
dev_kfree_skb(skb);
diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c
index ae8fb06cf38..bc62b012602 100644
--- a/drivers/usb/net/cdc_subset.c
+++ b/drivers/usb/net/cdc_subset.c
@@ -79,13 +79,19 @@ static int always_connected (struct usbnet *dev)
*
* 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 const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
};
-
#endif
@@ -159,6 +165,11 @@ static const struct driver_info epson2888_info = {
#endif /* CONFIG_USB_EPSON2888 */
+/*-------------------------------------------------------------------------
+ *
+ * info from Jonathan McDowell <noodles@earth.li>
+ *
+ *-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_KC2190
#define HAVE_HARDWARE
static const struct driver_info kc2190_info = {
@@ -223,6 +234,10 @@ static const struct usb_device_id products [] = {
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
@@ -314,13 +329,13 @@ static struct usb_driver cdc_subset_driver = {
static int __init cdc_subset_init(void)
{
- return usb_register(&cdc_subset_driver);
+ return usb_register(&cdc_subset_driver);
}
module_init(cdc_subset_init);
static void __exit cdc_subset_exit(void)
{
- usb_deregister(&cdc_subset_driver);
+ usb_deregister(&cdc_subset_driver);
}
module_exit(cdc_subset_exit);
diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c
new file mode 100644
index 00000000000..a6763860147
--- /dev/null
+++ b/drivers/usb/net/dm9601.c
@@ -0,0 +1,619 @@
+/*
+ * Davicom DM9601 USB 1.1 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/init.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 "usbnet.h"
+
+/* datasheet:
+ http://www.davicom.com.tw/big5/download/Data%20Sheet/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_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)
+{
+ devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ DM_READ_REGS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+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)
+{
+ devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REGS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+ devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void dm_write_async_callback(struct urb *urb)
+{
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+ if (urb->status < 0)
+ printk(KERN_DEBUG "dm_write_async_callback() failed with %d",
+ urb->status);
+
+ kfree(req);
+ usb_free_urb(urb);
+}
+
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REGS;
+ req->wValue = 0;
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = cpu_to_le16(length);
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, length,
+ dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
+ reg, value);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REG;
+ req->wValue = cpu_to_le16(value);
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = 0;
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, NULL, 0, dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *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;
+
+ 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) {
+ deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+ ret = dm_read(dev, DM_SHARED_DATA, 2, value);
+
+ devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d",
+ 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, u16 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 ? 0x1c : 0x14);
+
+ for (i = 0; i < DM_TIMEOUT; i++) {
+ u8 tmp;
+
+ 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) {
+ deverr(dev, "%s write timed out!", 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);
+ u16 *ebuf = (u16 *) 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);
+
+ u16 res;
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ return 0;
+ }
+
+ dm_read_shared_word(dev, 1, loc, &res);
+
+ devdbg(dev,
+ "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
+ 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);
+ u16 res = cpu_to_le16(val);
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ return;
+ }
+
+ devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
+ 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 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 = 0x01;
+
+ 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 || net->mc_count > DM_MAX_MCAST) {
+ rx_ctl |= 0x04;
+ } else if (net->mc_count) {
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
+
+ for (i = 0; i < net->mc_count; i++) {
+ u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_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 int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret)
+ goto out;
+
+ dev->net->do_ioctl = dm9601_ioctl;
+ dev->net->set_multicast_list = dm9601_set_multicast;
+ 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;
+ dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+
+ 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 */
+ ret = dm_write_reg(dev, DM_NET_CTRL, 1);
+ udelay(20);
+
+ /* read MAC */
+ ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
+ if (ret < 0) {
+ printk(KERN_ERR "Error reading MAC address\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+
+ /* 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:
+ b0: rx status
+ b1: packet length (incl crc) low
+ b2: packet length (incl crc) high
+ b3..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->stats.rx_fifo_errors++;
+ if (status & 0x02) dev->stats.rx_crc_errors++;
+ if (status & 0x04) dev->stats.rx_frame_errors++;
+ if (status & 0x20) dev->stats.rx_missed_errors++;
+ if (status & 0x90) dev->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;
+
+ /* format:
+ b0: packet length low
+ b1: packet length high
+ b3..n: packet data
+ */
+
+ if (skb_headroom(skb) < DM_TX_OVERHEAD) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ __skb_push(skb, DM_TX_OVERHEAD);
+
+ len = skb->len;
+ /* usbnet adds padding if length is a multiple of packet size
+ if so, adjust length value in header */
+ if ((len % dev->maxpacket) == 0)
+ len++;
+
+ 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) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ usbnet_defer_kevent (dev, EVENT_LINK_RESET);
+ }
+ else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "Link Status is: %d", link);
+ }
+}
+
+static int dm9601_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+
+ devdbg(dev, "link_reset() speed: %d duplex: %d",
+ ecmd.speed, ecmd.duplex);
+
+ return 0;
+}
+
+static const struct driver_info dm9601_info = {
+ .description = "Davicom DM9601 USB Ethernet",
+ .flags = FLAG_ETHER,
+ .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,
+ },
+ {}, // 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,
+};
+
+static int __init dm9601_init(void)
+{
+ return usb_register(&dm9601_driver);
+}
+
+static void __exit dm9601_exit(void)
+{
+ usb_deregister(&dm9601_driver);
+}
+
+module_init(dm9601_init);
+module_exit(dm9601_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index d257a8e026d..031cf5ca4db 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -157,7 +157,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
skb->data = memmove(skb->head + (4 + 4*1),
skb->data, skb->len);
- skb->tail = skb->data + skb->len;
+ skb_set_tail_pointer(skb, skb->len);
}
} else {
struct sk_buff *skb2;
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index de95268ae4b..a0cc05d21a6 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -636,8 +636,6 @@ static void kaweth_usb_receive(struct urb *urb)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- skb->dev = net;
-
eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
skb_put(skb, pkt_len);
diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
index ccebfdef475..19bf8dae70c 100644
--- a/drivers/usb/net/net1080.c
+++ b/drivers/usb/net/net1080.c
@@ -520,7 +520,7 @@ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
skb->data = memmove(skb->head
+ sizeof (struct nc_header),
skb->data, skb->len);
- skb->tail = skb->data + len;
+ skb_set_tail_pointer(skb, len);
goto encapsulate;
}
}
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index d48c024cff5..a05fd97e5bc 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -316,6 +316,7 @@ static int update_eth_regs_async(pegasus_t * pegasus)
return ret;
}
+/* Returns 0 on success, error on failure */
static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
{
int i;
@@ -574,7 +575,6 @@ static void fill_skb_pool(pegasus_t * pegasus)
*/
if (pegasus->rx_pool[i] == NULL)
return;
- pegasus->rx_pool[i]->dev = pegasus->net;
skb_reserve(pegasus->rx_pool[i], 2);
}
}
@@ -847,10 +847,6 @@ static void intr_callback(struct urb *urb)
* d[0].NO_CARRIER kicks in only with failed TX.
* ... so monitoring with MII may be safest.
*/
- if (d[0] & NO_CARRIER)
- netif_carrier_off(net);
- else
- netif_carrier_on(net);
/* bytes 3-4 == rx_lostpkt, reg 2E/2F */
pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
@@ -883,7 +879,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
netif_stop_queue(net);
((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
- memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
+ 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,
@@ -950,7 +946,7 @@ 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))
+ if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))
return;
if (tmp & BMSR_LSTATUS)
@@ -1408,8 +1404,10 @@ static void pegasus_disconnect(struct usb_interface *intf)
unlink_all_urbs(pegasus);
free_all_urbs(pegasus);
free_skb_pool(pegasus);
- if (pegasus->rx_skb)
+ if (pegasus->rx_skb != NULL) {
dev_kfree_skb(pegasus->rx_skb);
+ pegasus->rx_skb = NULL;
+ }
free_netdev(pegasus->net);
}
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index 39a21c74fdf..980e4aaa97a 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -253,6 +253,7 @@ struct rndis_keepalive_c { /* IN (optionally OUT) */
* of that mess as possible.
*/
#define OID_802_3_PERMANENT_ADDRESS ccpu2(0x01010101)
+#define OID_GEN_MAXIMUM_FRAME_SIZE ccpu2(0x00010106)
#define OID_GEN_CURRENT_PACKET_FILTER ccpu2(0x0001010e)
/*
@@ -349,7 +350,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
case RNDIS_MSG_INDICATE: { /* fault */
// struct rndis_indicate *msg = (void *)buf;
dev_info(&info->control->dev,
- "rndis fault indication\n");
+ "rndis fault indication\n");
}
break;
case RNDIS_MSG_KEEPALIVE: { /* ping *