ChangeSet 1.2020.1.31, 2005/03/07 22:51:55-08:00, [EMAIL PROTECTED]

[PATCH] USB: Add ASIX AX88772 10/100 Ethernet support to usbnet

* Add support for the ASIX AX88772 10/100 Ethernet chip
* Fix ax8817x_bind to use allocated buffer to avoid DMA on the stack
* Fix ax8817x_bind error handling to ensure all resources are freed on failure
* Fix ax8817x_get_eeprom routines to return valid eeprom data


Signed-off-by: David Hollis <[EMAIL PROTECTED]>
Acked-by: David Brownell <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>


 drivers/usb/net/Kconfig  |    4 
 drivers/usb/net/usbnet.c |  406 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 380 insertions(+), 30 deletions(-)


diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
--- a/drivers/usb/net/Kconfig   2005-03-08 16:53:26 -08:00
+++ b/drivers/usb/net/Kconfig   2005-03-08 16:53:26 -08:00
@@ -260,13 +260,13 @@
        depends on USB_USBNET
 
 config USB_AX8817X
-       boolean "ASIX AX88172 Based USB 2.0 Ethernet Devices"
+       boolean "ASIX AX88xxx Based USB 2.0 Ethernet Devices"
        depends on USB_USBNET && NET_ETHERNET
        select CRC32
        select MII
        default y
        help
-         This option adds support for ASIX AX88172 based USB 2.0
+         This option adds support for ASIX AX88xxx based USB 2.0
          10/100 Ethernet devices.
 
          This driver should work with at least the following devices:
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c  2005-03-08 16:53:26 -08:00
+++ b/drivers/usb/net/usbnet.c  2005-03-08 16:53:26 -08:00
@@ -2,7 +2,8 @@
  * USB Networking Links
  * Copyright (C) 2000-2003 by David Brownell <[EMAIL PROTECTED]>
  * Copyright (C) 2002 Pavel Machek <[EMAIL PROTECTED]>
- * Copyright (C) 2003 David Hollis <[EMAIL PROTECTED]>
+ * Copyright (C) 2003-2005 David Hollis <[EMAIL PROTECTED]>
+ * Copyright (C) 2005 Phil Chang <[EMAIL PROTECTED]>
  * Copyright (c) 2002-2003 TiVo Inc.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -109,6 +110,7 @@
  *             (Neil Bortnak)
  * 03-nov-2004 Trivial patch for KC2190 (KC-190) chip. (Jonathan McDowell)
  *
+ * 01-feb-2005 AX88772 support (Phil Chang & Dave Hollis)
  *-------------------------------------------------------------------------*/
 
 // #define     DEBUG                   // error path messages, extra info
@@ -222,6 +224,8 @@
 #define FLAG_NO_SETINT 0x0010          /* device can't set_interface() */
 #define FLAG_ETHER     0x0020          /* maybe use "eth%d" names */
 
+#define FLAG_FRAMING_AX 0x0040          /* AX88772/178 packets */
+
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
 
@@ -435,6 +439,8 @@
 #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_WRITE_RX_CTL            0x10
 #define AX_CMD_READ_IPG012             0x11
 #define AX_CMD_WRITE_IPG0              0x12
@@ -447,6 +453,10 @@
 #define AX_CMD_READ_MONITOR_MODE       0x1c
 #define AX_CMD_WRITE_MONITOR_MODE      0x1d
 #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 AX88772_CMD_READ_NODE_ID       0x13
 
 #define AX_MONITOR_MODE                        0x01
 #define AX_MONITOR_LINK                        0x02
@@ -458,6 +468,23 @@
 
 #define AX_INTERRUPT_BUFSIZE           8
 
+#define AX_EEPROM_LEN                  0x40
+
+#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
+
+#define AX_EEPROM_MAGIC                        0xdeadbeef
+
 /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
 struct ax8817x_data {
        u8 multi_filter[AX_MCAST_FILTER_SIZE];
@@ -514,18 +541,16 @@
        int link;
 
        if (urb->status < 0) {
-               printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d",
+               devdbg(dev,"ax8817x_interrupt_complete() failed with %d",
                        urb->status);
        } else {
-               if (data->int_buf[5] == 0x90) {
-                       link = data->int_buf[2] & 0x01;
-                       if (netif_carrier_ok(dev->net) != link) {
-                               if (link)
-                                       netif_carrier_on(dev->net);
-                               else
-                                       netif_carrier_off(dev->net);
-                               devdbg(dev, "ax8817x - Link Status is: %d", 
link);
-                       }
+               link = data->int_buf[2] & 0x01;
+               if (netif_carrier_ok(dev->net) != link) {
+                       if (link)
+                               netif_carrier_on(dev->net);
+                       else
+                               netif_carrier_off(dev->net);
+                       devdbg(dev, "ax8817x - Link Status is: %d", link);
                }
                usb_submit_urb(data->int_urb, GFP_ATOMIC);
        }
@@ -674,6 +699,11 @@
        return 0;
 }
 
+static int ax8817x_get_eeprom_len(struct net_device *net)
+{
+       return AX_EEPROM_LEN;
+}
+
 static int ax8817x_get_eeprom(struct net_device *net,
                              struct ethtool_eeprom *eeprom, u8 *data)
 {
@@ -687,13 +717,15 @@
        if (eeprom->len % 2)
                return -EINVAL;
 
+       eeprom->magic = AX_EEPROM_MAGIC;
+
        /* ax8817x returns 2 bytes from eeprom on read */
        for (i=0; i < eeprom->len / 2; i++) {
                if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 
                        eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
                        return -EINVAL;
        }
-       return i * 2;
+       return 0;
 }
 
 static void ax8817x_get_drvinfo (struct net_device *net,
@@ -728,6 +760,7 @@
        .set_msglevel           = usbnet_set_msglevel,
        .get_wol                = ax8817x_get_wol,
        .set_wol                = ax8817x_set_wol,
+       .get_eeprom_len         = ax8817x_get_eeprom_len,
        .get_eeprom             = ax8817x_get_eeprom,
        .get_settings           = ax8817x_get_settings,
        .set_settings           = ax8817x_set_settings,
@@ -735,27 +768,26 @@
 
 static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-       int ret;
-       u8 buf[6];
+       int ret = 0;
+       void *buf;
        int i;
        unsigned long gpio_bits = dev->driver_info->data;
        struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
 
-       dev->in = usb_rcvbulkpipe(dev->udev, 3);
-       dev->out = usb_sndbulkpipe(dev->udev, 2);
+       get_endpoints(dev,intf);
 
-       // allocate irq urb
        if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) {
                dbg ("%s: cannot allocate interrupt URB",
                        dev->net->name);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out1;
        }
        
        if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == 
NULL) {
                dbg ("%s: cannot allocate memory for interrupt buffer",
                        dev->net->name);
-               usb_free_urb(data->int_urb);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out1;
        }
        memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
 
@@ -765,36 +797,43 @@
                ax8817x_interrupt_complete, dev,
                dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
 
+       buf = kmalloc(ETH_ALEN, GFP_KERNEL);
+       if(!buf) {
+               ret = -ENOMEM;
+               goto out2;
+       }
+
        /* Toggle the GPIOs in a manufacturer/model specific way */
        for (i = 2; i >= 0; i--) {
                if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
                                        (gpio_bits >> (i * 8)) & 0xff, 0, 0,
                                        buf)) < 0)
-                       return ret;
+                       goto out3;
                msleep(5);
        }
 
        if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, 
buf)) < 0) {
                dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret);
-               return ret;
+               goto out3;
        }
 
        /* Get the MAC address */
        memset(buf, 0, ETH_ALEN);
        if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 
0) {
                dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
-               return ret;
+               goto out3;
        }
        memcpy(dev->net->dev_addr, buf, ETH_ALEN);
 
        /* Get the PHY id */
        if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 
0) {
                dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret);
-               return ret;
+               goto out3;
        } else if (ret < 2) {
                /* this should always return 2 bytes */
                dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", 
ret);
-               return -EIO;
+               ret = -EIO;
+               goto out3;
        }
 
        /* Initialize MII structure */
@@ -803,7 +842,7 @@
        dev->mii.mdio_write = ax8817x_mdio_write;
        dev->mii.phy_id_mask = 0x3f;
        dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = buf[1];
+       dev->mii.phy_id = *((u8 *)buf + 1);
 
        dev->net->set_multicast_list = ax8817x_set_multicast;
        dev->net->ethtool_ops = &ax8817x_ethtool_ops;
@@ -816,11 +855,17 @@
 
        if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
                dbg("Failed to submit interrupt URB: %02x", ret);
-               usb_free_urb(data->int_urb);
-               return ret;
+               goto out2;
        }
 
        return 0;
+out3:
+       kfree(buf);
+out2:
+       kfree(data->int_buf);
+out1:
+       usb_free_urb(data->int_urb);
+       return ret;
 }
 
 static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -832,6 +877,290 @@
        kfree(data->int_buf);
 }
 
+static struct ethtool_ops ax88772_ethtool_ops = {
+       .get_drvinfo            = ax8817x_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+       .get_msglevel           = usbnet_get_msglevel,
+       .set_msglevel           = usbnet_set_msglevel,
+       .get_wol                = ax8817x_get_wol,
+       .set_wol                = ax8817x_set_wol,
+       .get_eeprom_len         = ax8817x_get_eeprom_len,
+       .get_eeprom             = ax8817x_get_eeprom,
+       .get_settings           = ax8817x_get_settings,
+       .set_settings           = ax8817x_set_settings,
+};
+
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       int ret;
+       void *buf;
+       struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
+
+       get_endpoints(dev,intf);
+
+       if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) {
+               dbg ("Cannot allocate interrupt URB");
+               ret = -ENOMEM;
+               goto out1;
+       }
+       
+       if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == 
NULL) {
+               dbg ("Cannot allocate memory for interrupt buffer");
+               ret = -ENOMEM;
+               goto out1;
+       }
+       memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
+
+       usb_fill_int_urb (data->int_urb, dev->udev,
+               usb_rcvintpipe (dev->udev, 1),
+               data->int_buf, AX_INTERRUPT_BUFSIZE,
+               ax8817x_interrupt_complete, dev,
+               dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
+
+       buf = kmalloc(6, GFP_KERNEL);
+       if(!buf) {
+               dbg ("Cannot allocate memory for buffer");
+               ret = -ENOMEM;
+               goto out2;
+       }
+
+       if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+                                    0x00B0, 0, 0, buf)) < 0)
+               goto out3;
+
+       msleep(5);
+       if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, 
buf)) < 0) {
+               dbg("Select PHY #1 failed: %d", ret);
+               goto out3;
+       }
+
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, 
buf)) < 0) {
+               dbg("Failed to power down internal PHY: %d", ret);
+               goto out3;
+       }
+
+       msleep(150);
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, 
buf)) < 0) {
+               dbg("Failed to perform software reset: %d", ret);
+               goto out3;
+       }
+
+       msleep(150);
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | 
AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+               dbg("Failed to set Internal/External PHY reset control: %d", 
ret);
+               goto out3;
+       }
+
+       msleep(150);
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0,
+                              buf)) < 0) {
+               dbg("Failed to reset RX_CTL: %d", ret);
+               goto out3;
+       }
+
+       /* Get the MAC address */
+       memset(buf, 0, ETH_ALEN);
+       if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, 
ETH_ALEN, buf)) < 0) {
+               dbg("Failed to read MAC address: %d", ret);
+               goto out3;
+       }
+       memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+       if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 
0) {
+               dbg("Enabling software MII failed: %d", ret);
+               goto out3;
+       }
+
+       if (((ret =
+             ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 
0)
+           || (*((u16 *)buf) != 0x003b)) {
+               dbg("Read PHY register 2 must be 0x3b00: %d", ret);
+               goto out3;
+       }
+
+       /* Initialize MII structure */
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = ax8817x_mdio_read;
+       dev->mii.mdio_write = ax8817x_mdio_write;
+       dev->mii.phy_id_mask = 0xff;
+       dev->mii.reg_num_mask = 0xff;
+
+       /* Get the PHY id */
+       if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 
0) {
+               dbg("Error reading PHY ID: %02x", ret);
+               goto out3;
+       } else if (ret < 2) {
+               /* this should always return 2 bytes */
+               dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x",
+                   ret);
+               ret = -EIO;
+               goto out3;
+       }
+       dev->mii.phy_id = *((u8 *)buf + 1);
+
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, 
buf)) < 0) {
+               dbg("Set external PHY reset pin level: %d", ret);
+               goto out3;
+       }
+       msleep(150);
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | 
AX_SWRESET_PRL, 0, 0, buf)) < 0) {
+               dbg("Set Internal/External PHY reset control: %d", ret);
+               goto out3;
+       }
+       msleep(150);
+
+
+       dev->net->set_multicast_list = ax8817x_set_multicast;
+       dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+       ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+                       cpu_to_le16(BMCR_RESET));
+       ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+                       cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA));
+       mii_nway_restart(&dev->mii);
+
+       if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0x0336, 0, 
0, buf)) < 0) {
+               dbg("Write medium mode register: %d", ret);
+               goto out3;
+       }
+
+       if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, 
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,AX88772_IPG2_DEFAULT, 0, buf)) < 0) 
{
+               dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
+               goto out3;
+       }
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
+               dbg("Failed to set hardware MII: %02x", ret);
+               goto out3;
+       }
+
+       /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+       if ((ret =
+            ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
+                              buf)) < 0) {
+               dbg("Reset RX_CTL failed: %d", ret);
+               goto out3;
+       }
+
+       if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
+               dbg("Failed to submit interrupt URB: %02x", ret);
+               goto out3;
+       }
+
+       kfree(buf);
+
+       return 0;
+
+out3:
+       kfree(buf);
+out2:
+       kfree(data->int_buf);
+out1:
+       usb_free_urb(data->int_urb);
+
+       return ret;
+}
+
+static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       u32 *header;
+       char *packet;
+       struct sk_buff *ax_skb;
+       u16 size;
+
+       header = (u32 *) skb->data;
+       le32_to_cpus(header);
+       packet = (char *)(header + 1);
+
+       skb_pull(skb, 4);
+
+       while (skb->len > 0) {
+               if ((short)(*header & 0x0000ffff) !=
+                   ~((short)((*header & 0xffff0000) >> 16))) {
+                       devdbg(dev,"header length data is error");
+               }
+               /* get the packet length */
+               size = (u16) (*header & 0x0000ffff);
+
+               if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+                       return 2;
+               if (size > ETH_FRAME_LEN) {
+                       devdbg(dev,"invalid rx length %d", size);
+                       return 0;
+               }
+               ax_skb = skb_clone(skb, GFP_ATOMIC);
+               if (ax_skb) {
+                       ax_skb->len = size;
+                       ax_skb->data = packet;
+                       ax_skb->tail = packet + size;
+                       skb_return(dev, ax_skb);
+               } else {
+                       return 0;
+               }
+
+               skb_pull(skb, (size + 1) & 0xfffe);
+
+               if (skb->len == 0)
+                       break;
+
+               header = (u32 *) skb->data;
+               le32_to_cpus(header);
+               packet = (char *)(header + 1);
+               skb_pull(skb, 4);
+       }
+
+       if (skb->len < 0) {
+               devdbg(dev,"invalid rx length %d", skb->len);
+               return 0;
+       }
+       return 1;
+}
+
+static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff 
*skb,
+                                       int flags)
+{
+       int padlen;
+       int headroom = skb_headroom(skb);
+       int tailroom = skb_tailroom(skb);
+       u32 *packet_len;
+       u32 *padbytes_ptr;
+
+       padlen = ((skb->len + 4) % 512) ? 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->tail = skb->data + 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 = (u32 *) skb_push(skb, 4);
+
+       packet_len = (u32 *) skb->data;
+       *packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+
+       if ((skb->len % 512) == 0) {
+               padbytes_ptr = (u32 *) skb->tail;
+               *padbytes_ptr = 0xffff0000;
+               skb_put(skb, padlen);
+       }
+       return skb;
+}
+
 static const struct driver_info ax8817x_info = {
        .description = "ASIX AX8817x USB 2.0 Ethernet",
        .bind = ax8817x_bind,
@@ -864,6 +1193,16 @@
        .data = 0x001f1d1f,
 };
 
+static const struct driver_info ax88772_info = {
+       .description = "ASIX AX88772 USB 2.0 Ethernet",
+       .bind = ax88772_bind,
+       .unbind = ax8817x_unbind,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88772_rx_fixup,
+       .tx_fixup = ax88772_tx_fixup,
+       .data = 0x00130103,
+};
+
 #endif /* CONFIG_USB_AX8817X */
 
 
@@ -2402,6 +2741,11 @@
                size = RNDIS_MAX_TRANSFER;
        else
 #endif
+#ifdef CONFIG_USB_AX8817X
+       if (dev->driver_info->flags & FLAG_FRAMING_AX)
+               size = 2048;
+       else
+#endif
                size = (sizeof (struct ethhdr) + dev->net->mtu);
 
        if ((skb = alloc_skb (size, flags)) == NULL) {
@@ -2677,6 +3021,8 @@
                        framing = "Zaurus";
                else if (dev->driver_info->flags & FLAG_FRAMING_RN)
                        framing = "RNDIS";
+               else if (dev->driver_info->flags & FLAG_FRAMING_AX)
+                       framing = "ASIX";
                else
                        framing = "simple";
 
@@ -3290,6 +3636,10 @@
        // goodway corp usb gwusb2e
        USB_DEVICE (0x1631, 0x6200),
        .driver_info = (unsigned long) &ax8817x_info,
+}, {
+       // ASIX AX88772 10/100
+        USB_DEVICE (0x0b95, 0x7720),
+        .driver_info = (unsigned long) &ax88772_info,
 },
 #endif
 



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id396&op=click
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to