1*b4cdae20SChristian Riesch /* 2*b4cdae20SChristian Riesch * ASIX AX8817X based USB 2.0 Ethernet Devices 3*b4cdae20SChristian Riesch * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> 4*b4cdae20SChristian Riesch * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 5*b4cdae20SChristian Riesch * Copyright (C) 2006 James Painter <jamie.painter@iname.com> 6*b4cdae20SChristian Riesch * Copyright (c) 2002-2003 TiVo Inc. 7*b4cdae20SChristian Riesch * 8*b4cdae20SChristian Riesch * This program is free software; you can redistribute it and/or modify 9*b4cdae20SChristian Riesch * it under the terms of the GNU General Public License as published by 10*b4cdae20SChristian Riesch * the Free Software Foundation; either version 2 of the License, or 11*b4cdae20SChristian Riesch * (at your option) any later version. 12*b4cdae20SChristian Riesch * 13*b4cdae20SChristian Riesch * This program is distributed in the hope that it will be useful, 14*b4cdae20SChristian Riesch * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*b4cdae20SChristian Riesch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*b4cdae20SChristian Riesch * GNU General Public License for more details. 17*b4cdae20SChristian Riesch * 18*b4cdae20SChristian Riesch * You should have received a copy of the GNU General Public License 19*b4cdae20SChristian Riesch * along with this program; if not, write to the Free Software 20*b4cdae20SChristian Riesch * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*b4cdae20SChristian Riesch */ 22*b4cdae20SChristian Riesch 23*b4cdae20SChristian Riesch // #define DEBUG // error path messages, extra info 24*b4cdae20SChristian Riesch // #define VERBOSE // more; success messages 25*b4cdae20SChristian Riesch 26*b4cdae20SChristian Riesch #include <linux/module.h> 27*b4cdae20SChristian Riesch #include <linux/kmod.h> 28*b4cdae20SChristian Riesch #include <linux/init.h> 29*b4cdae20SChristian Riesch #include <linux/netdevice.h> 30*b4cdae20SChristian Riesch #include <linux/etherdevice.h> 31*b4cdae20SChristian Riesch #include <linux/ethtool.h> 32*b4cdae20SChristian Riesch #include <linux/workqueue.h> 33*b4cdae20SChristian Riesch #include <linux/mii.h> 34*b4cdae20SChristian Riesch #include <linux/usb.h> 35*b4cdae20SChristian Riesch #include <linux/crc32.h> 36*b4cdae20SChristian Riesch #include <linux/usb/usbnet.h> 37*b4cdae20SChristian Riesch #include <linux/slab.h> 38*b4cdae20SChristian Riesch #include <linux/if_vlan.h> 39*b4cdae20SChristian Riesch 40*b4cdae20SChristian Riesch #define DRIVER_VERSION "22-Dec-2011" 41*b4cdae20SChristian Riesch #define DRIVER_NAME "asix" 42*b4cdae20SChristian Riesch 43*b4cdae20SChristian Riesch /* ASIX AX8817X based USB 2.0 Ethernet Devices */ 44*b4cdae20SChristian Riesch 45*b4cdae20SChristian Riesch #define AX_CMD_SET_SW_MII 0x06 46*b4cdae20SChristian Riesch #define AX_CMD_READ_MII_REG 0x07 47*b4cdae20SChristian Riesch #define AX_CMD_WRITE_MII_REG 0x08 48*b4cdae20SChristian Riesch #define AX_CMD_SET_HW_MII 0x0a 49*b4cdae20SChristian Riesch #define AX_CMD_READ_EEPROM 0x0b 50*b4cdae20SChristian Riesch #define AX_CMD_WRITE_EEPROM 0x0c 51*b4cdae20SChristian Riesch #define AX_CMD_WRITE_ENABLE 0x0d 52*b4cdae20SChristian Riesch #define AX_CMD_WRITE_DISABLE 0x0e 53*b4cdae20SChristian Riesch #define AX_CMD_READ_RX_CTL 0x0f 54*b4cdae20SChristian Riesch #define AX_CMD_WRITE_RX_CTL 0x10 55*b4cdae20SChristian Riesch #define AX_CMD_READ_IPG012 0x11 56*b4cdae20SChristian Riesch #define AX_CMD_WRITE_IPG0 0x12 57*b4cdae20SChristian Riesch #define AX_CMD_WRITE_IPG1 0x13 58*b4cdae20SChristian Riesch #define AX_CMD_READ_NODE_ID 0x13 59*b4cdae20SChristian Riesch #define AX_CMD_WRITE_NODE_ID 0x14 60*b4cdae20SChristian Riesch #define AX_CMD_WRITE_IPG2 0x14 61*b4cdae20SChristian Riesch #define AX_CMD_WRITE_MULTI_FILTER 0x16 62*b4cdae20SChristian Riesch #define AX88172_CMD_READ_NODE_ID 0x17 63*b4cdae20SChristian Riesch #define AX_CMD_READ_PHY_ID 0x19 64*b4cdae20SChristian Riesch #define AX_CMD_READ_MEDIUM_STATUS 0x1a 65*b4cdae20SChristian Riesch #define AX_CMD_WRITE_MEDIUM_MODE 0x1b 66*b4cdae20SChristian Riesch #define AX_CMD_READ_MONITOR_MODE 0x1c 67*b4cdae20SChristian Riesch #define AX_CMD_WRITE_MONITOR_MODE 0x1d 68*b4cdae20SChristian Riesch #define AX_CMD_READ_GPIOS 0x1e 69*b4cdae20SChristian Riesch #define AX_CMD_WRITE_GPIOS 0x1f 70*b4cdae20SChristian Riesch #define AX_CMD_SW_RESET 0x20 71*b4cdae20SChristian Riesch #define AX_CMD_SW_PHY_STATUS 0x21 72*b4cdae20SChristian Riesch #define AX_CMD_SW_PHY_SELECT 0x22 73*b4cdae20SChristian Riesch 74*b4cdae20SChristian Riesch #define AX_MONITOR_MODE 0x01 75*b4cdae20SChristian Riesch #define AX_MONITOR_LINK 0x02 76*b4cdae20SChristian Riesch #define AX_MONITOR_MAGIC 0x04 77*b4cdae20SChristian Riesch #define AX_MONITOR_HSFS 0x10 78*b4cdae20SChristian Riesch 79*b4cdae20SChristian Riesch /* AX88172 Medium Status Register values */ 80*b4cdae20SChristian Riesch #define AX88172_MEDIUM_FD 0x02 81*b4cdae20SChristian Riesch #define AX88172_MEDIUM_TX 0x04 82*b4cdae20SChristian Riesch #define AX88172_MEDIUM_FC 0x10 83*b4cdae20SChristian Riesch #define AX88172_MEDIUM_DEFAULT \ 84*b4cdae20SChristian Riesch ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) 85*b4cdae20SChristian Riesch 86*b4cdae20SChristian Riesch #define AX_MCAST_FILTER_SIZE 8 87*b4cdae20SChristian Riesch #define AX_MAX_MCAST 64 88*b4cdae20SChristian Riesch 89*b4cdae20SChristian Riesch #define AX_SWRESET_CLEAR 0x00 90*b4cdae20SChristian Riesch #define AX_SWRESET_RR 0x01 91*b4cdae20SChristian Riesch #define AX_SWRESET_RT 0x02 92*b4cdae20SChristian Riesch #define AX_SWRESET_PRTE 0x04 93*b4cdae20SChristian Riesch #define AX_SWRESET_PRL 0x08 94*b4cdae20SChristian Riesch #define AX_SWRESET_BZ 0x10 95*b4cdae20SChristian Riesch #define AX_SWRESET_IPRL 0x20 96*b4cdae20SChristian Riesch #define AX_SWRESET_IPPD 0x40 97*b4cdae20SChristian Riesch 98*b4cdae20SChristian Riesch #define AX88772_IPG0_DEFAULT 0x15 99*b4cdae20SChristian Riesch #define AX88772_IPG1_DEFAULT 0x0c 100*b4cdae20SChristian Riesch #define AX88772_IPG2_DEFAULT 0x12 101*b4cdae20SChristian Riesch 102*b4cdae20SChristian Riesch /* AX88772 & AX88178 Medium Mode Register */ 103*b4cdae20SChristian Riesch #define AX_MEDIUM_PF 0x0080 104*b4cdae20SChristian Riesch #define AX_MEDIUM_JFE 0x0040 105*b4cdae20SChristian Riesch #define AX_MEDIUM_TFC 0x0020 106*b4cdae20SChristian Riesch #define AX_MEDIUM_RFC 0x0010 107*b4cdae20SChristian Riesch #define AX_MEDIUM_ENCK 0x0008 108*b4cdae20SChristian Riesch #define AX_MEDIUM_AC 0x0004 109*b4cdae20SChristian Riesch #define AX_MEDIUM_FD 0x0002 110*b4cdae20SChristian Riesch #define AX_MEDIUM_GM 0x0001 111*b4cdae20SChristian Riesch #define AX_MEDIUM_SM 0x1000 112*b4cdae20SChristian Riesch #define AX_MEDIUM_SBP 0x0800 113*b4cdae20SChristian Riesch #define AX_MEDIUM_PS 0x0200 114*b4cdae20SChristian Riesch #define AX_MEDIUM_RE 0x0100 115*b4cdae20SChristian Riesch 116*b4cdae20SChristian Riesch #define AX88178_MEDIUM_DEFAULT \ 117*b4cdae20SChristian Riesch (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ 118*b4cdae20SChristian Riesch AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ 119*b4cdae20SChristian Riesch AX_MEDIUM_RE) 120*b4cdae20SChristian Riesch 121*b4cdae20SChristian Riesch #define AX88772_MEDIUM_DEFAULT \ 122*b4cdae20SChristian Riesch (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ 123*b4cdae20SChristian Riesch AX_MEDIUM_TFC | AX_MEDIUM_PS | \ 124*b4cdae20SChristian Riesch AX_MEDIUM_AC | AX_MEDIUM_RE) 125*b4cdae20SChristian Riesch 126*b4cdae20SChristian Riesch /* AX88772 & AX88178 RX_CTL values */ 127*b4cdae20SChristian Riesch #define AX_RX_CTL_SO 0x0080 128*b4cdae20SChristian Riesch #define AX_RX_CTL_AP 0x0020 129*b4cdae20SChristian Riesch #define AX_RX_CTL_AM 0x0010 130*b4cdae20SChristian Riesch #define AX_RX_CTL_AB 0x0008 131*b4cdae20SChristian Riesch #define AX_RX_CTL_SEP 0x0004 132*b4cdae20SChristian Riesch #define AX_RX_CTL_AMALL 0x0002 133*b4cdae20SChristian Riesch #define AX_RX_CTL_PRO 0x0001 134*b4cdae20SChristian Riesch #define AX_RX_CTL_MFB_2048 0x0000 135*b4cdae20SChristian Riesch #define AX_RX_CTL_MFB_4096 0x0100 136*b4cdae20SChristian Riesch #define AX_RX_CTL_MFB_8192 0x0200 137*b4cdae20SChristian Riesch #define AX_RX_CTL_MFB_16384 0x0300 138*b4cdae20SChristian Riesch 139*b4cdae20SChristian Riesch #define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) 140*b4cdae20SChristian Riesch 141*b4cdae20SChristian Riesch /* GPIO 0 .. 2 toggles */ 142*b4cdae20SChristian Riesch #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ 143*b4cdae20SChristian Riesch #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ 144*b4cdae20SChristian Riesch #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ 145*b4cdae20SChristian Riesch #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ 146*b4cdae20SChristian Riesch #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ 147*b4cdae20SChristian Riesch #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ 148*b4cdae20SChristian Riesch #define AX_GPIO_RESERVED 0x40 /* Reserved */ 149*b4cdae20SChristian Riesch #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ 150*b4cdae20SChristian Riesch 151*b4cdae20SChristian Riesch #define AX_EEPROM_MAGIC 0xdeadbeef 152*b4cdae20SChristian Riesch #define AX88172_EEPROM_LEN 0x40 153*b4cdae20SChristian Riesch #define AX88772_EEPROM_LEN 0xff 154*b4cdae20SChristian Riesch 155*b4cdae20SChristian Riesch #define PHY_MODE_MARVELL 0x0000 156*b4cdae20SChristian Riesch #define MII_MARVELL_LED_CTRL 0x0018 157*b4cdae20SChristian Riesch #define MII_MARVELL_STATUS 0x001b 158*b4cdae20SChristian Riesch #define MII_MARVELL_CTRL 0x0014 159*b4cdae20SChristian Riesch 160*b4cdae20SChristian Riesch #define MARVELL_LED_MANUAL 0x0019 161*b4cdae20SChristian Riesch 162*b4cdae20SChristian Riesch #define MARVELL_STATUS_HWCFG 0x0004 163*b4cdae20SChristian Riesch 164*b4cdae20SChristian Riesch #define MARVELL_CTRL_TXDELAY 0x0002 165*b4cdae20SChristian Riesch #define MARVELL_CTRL_RXDELAY 0x0080 166*b4cdae20SChristian Riesch 167*b4cdae20SChristian Riesch #define PHY_MODE_RTL8211CL 0x000C 168*b4cdae20SChristian Riesch 169*b4cdae20SChristian Riesch /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ 170*b4cdae20SChristian Riesch struct asix_data { 171*b4cdae20SChristian Riesch u8 multi_filter[AX_MCAST_FILTER_SIZE]; 172*b4cdae20SChristian Riesch u8 mac_addr[ETH_ALEN]; 173*b4cdae20SChristian Riesch u8 phymode; 174*b4cdae20SChristian Riesch u8 ledmode; 175*b4cdae20SChristian Riesch u8 eeprom_len; 176*b4cdae20SChristian Riesch }; 177*b4cdae20SChristian Riesch 178*b4cdae20SChristian Riesch struct ax88172_int_data { 179*b4cdae20SChristian Riesch __le16 res1; 180*b4cdae20SChristian Riesch u8 link; 181*b4cdae20SChristian Riesch __le16 res2; 182*b4cdae20SChristian Riesch u8 status; 183*b4cdae20SChristian Riesch __le16 res3; 184*b4cdae20SChristian Riesch } __packed; 185*b4cdae20SChristian Riesch 186*b4cdae20SChristian Riesch static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 187*b4cdae20SChristian Riesch u16 size, void *data) 188*b4cdae20SChristian Riesch { 189*b4cdae20SChristian Riesch void *buf; 190*b4cdae20SChristian Riesch int err = -ENOMEM; 191*b4cdae20SChristian Riesch 192*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 193*b4cdae20SChristian Riesch cmd, value, index, size); 194*b4cdae20SChristian Riesch 195*b4cdae20SChristian Riesch buf = kmalloc(size, GFP_KERNEL); 196*b4cdae20SChristian Riesch if (!buf) 197*b4cdae20SChristian Riesch goto out; 198*b4cdae20SChristian Riesch 199*b4cdae20SChristian Riesch err = usb_control_msg( 200*b4cdae20SChristian Riesch dev->udev, 201*b4cdae20SChristian Riesch usb_rcvctrlpipe(dev->udev, 0), 202*b4cdae20SChristian Riesch cmd, 203*b4cdae20SChristian Riesch USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 204*b4cdae20SChristian Riesch value, 205*b4cdae20SChristian Riesch index, 206*b4cdae20SChristian Riesch buf, 207*b4cdae20SChristian Riesch size, 208*b4cdae20SChristian Riesch USB_CTRL_GET_TIMEOUT); 209*b4cdae20SChristian Riesch if (err == size) 210*b4cdae20SChristian Riesch memcpy(data, buf, size); 211*b4cdae20SChristian Riesch else if (err >= 0) 212*b4cdae20SChristian Riesch err = -EINVAL; 213*b4cdae20SChristian Riesch kfree(buf); 214*b4cdae20SChristian Riesch 215*b4cdae20SChristian Riesch out: 216*b4cdae20SChristian Riesch return err; 217*b4cdae20SChristian Riesch } 218*b4cdae20SChristian Riesch 219*b4cdae20SChristian Riesch static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 220*b4cdae20SChristian Riesch u16 size, void *data) 221*b4cdae20SChristian Riesch { 222*b4cdae20SChristian Riesch void *buf = NULL; 223*b4cdae20SChristian Riesch int err = -ENOMEM; 224*b4cdae20SChristian Riesch 225*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 226*b4cdae20SChristian Riesch cmd, value, index, size); 227*b4cdae20SChristian Riesch 228*b4cdae20SChristian Riesch if (data) { 229*b4cdae20SChristian Riesch buf = kmemdup(data, size, GFP_KERNEL); 230*b4cdae20SChristian Riesch if (!buf) 231*b4cdae20SChristian Riesch goto out; 232*b4cdae20SChristian Riesch } 233*b4cdae20SChristian Riesch 234*b4cdae20SChristian Riesch err = usb_control_msg( 235*b4cdae20SChristian Riesch dev->udev, 236*b4cdae20SChristian Riesch usb_sndctrlpipe(dev->udev, 0), 237*b4cdae20SChristian Riesch cmd, 238*b4cdae20SChristian Riesch USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 239*b4cdae20SChristian Riesch value, 240*b4cdae20SChristian Riesch index, 241*b4cdae20SChristian Riesch buf, 242*b4cdae20SChristian Riesch size, 243*b4cdae20SChristian Riesch USB_CTRL_SET_TIMEOUT); 244*b4cdae20SChristian Riesch kfree(buf); 245*b4cdae20SChristian Riesch 246*b4cdae20SChristian Riesch out: 247*b4cdae20SChristian Riesch return err; 248*b4cdae20SChristian Riesch } 249*b4cdae20SChristian Riesch 250*b4cdae20SChristian Riesch static void asix_async_cmd_callback(struct urb *urb) 251*b4cdae20SChristian Riesch { 252*b4cdae20SChristian Riesch struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; 253*b4cdae20SChristian Riesch int status = urb->status; 254*b4cdae20SChristian Riesch 255*b4cdae20SChristian Riesch if (status < 0) 256*b4cdae20SChristian Riesch printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", 257*b4cdae20SChristian Riesch status); 258*b4cdae20SChristian Riesch 259*b4cdae20SChristian Riesch kfree(req); 260*b4cdae20SChristian Riesch usb_free_urb(urb); 261*b4cdae20SChristian Riesch } 262*b4cdae20SChristian Riesch 263*b4cdae20SChristian Riesch static void 264*b4cdae20SChristian Riesch asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, 265*b4cdae20SChristian Riesch u16 size, void *data) 266*b4cdae20SChristian Riesch { 267*b4cdae20SChristian Riesch struct usb_ctrlrequest *req; 268*b4cdae20SChristian Riesch int status; 269*b4cdae20SChristian Riesch struct urb *urb; 270*b4cdae20SChristian Riesch 271*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 272*b4cdae20SChristian Riesch cmd, value, index, size); 273*b4cdae20SChristian Riesch 274*b4cdae20SChristian Riesch urb = usb_alloc_urb(0, GFP_ATOMIC); 275*b4cdae20SChristian Riesch if (!urb) { 276*b4cdae20SChristian Riesch netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); 277*b4cdae20SChristian Riesch return; 278*b4cdae20SChristian Riesch } 279*b4cdae20SChristian Riesch 280*b4cdae20SChristian Riesch req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 281*b4cdae20SChristian Riesch if (!req) { 282*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to allocate memory for control request\n"); 283*b4cdae20SChristian Riesch usb_free_urb(urb); 284*b4cdae20SChristian Riesch return; 285*b4cdae20SChristian Riesch } 286*b4cdae20SChristian Riesch 287*b4cdae20SChristian Riesch req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; 288*b4cdae20SChristian Riesch req->bRequest = cmd; 289*b4cdae20SChristian Riesch req->wValue = cpu_to_le16(value); 290*b4cdae20SChristian Riesch req->wIndex = cpu_to_le16(index); 291*b4cdae20SChristian Riesch req->wLength = cpu_to_le16(size); 292*b4cdae20SChristian Riesch 293*b4cdae20SChristian Riesch usb_fill_control_urb(urb, dev->udev, 294*b4cdae20SChristian Riesch usb_sndctrlpipe(dev->udev, 0), 295*b4cdae20SChristian Riesch (void *)req, data, size, 296*b4cdae20SChristian Riesch asix_async_cmd_callback, req); 297*b4cdae20SChristian Riesch 298*b4cdae20SChristian Riesch status = usb_submit_urb(urb, GFP_ATOMIC); 299*b4cdae20SChristian Riesch if (status < 0) { 300*b4cdae20SChristian Riesch netdev_err(dev->net, "Error submitting the control message: status=%d\n", 301*b4cdae20SChristian Riesch status); 302*b4cdae20SChristian Riesch kfree(req); 303*b4cdae20SChristian Riesch usb_free_urb(urb); 304*b4cdae20SChristian Riesch } 305*b4cdae20SChristian Riesch } 306*b4cdae20SChristian Riesch 307*b4cdae20SChristian Riesch static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 308*b4cdae20SChristian Riesch { 309*b4cdae20SChristian Riesch int offset = 0; 310*b4cdae20SChristian Riesch 311*b4cdae20SChristian Riesch while (offset + sizeof(u32) < skb->len) { 312*b4cdae20SChristian Riesch struct sk_buff *ax_skb; 313*b4cdae20SChristian Riesch u16 size; 314*b4cdae20SChristian Riesch u32 header = get_unaligned_le32(skb->data + offset); 315*b4cdae20SChristian Riesch 316*b4cdae20SChristian Riesch offset += sizeof(u32); 317*b4cdae20SChristian Riesch 318*b4cdae20SChristian Riesch /* get the packet length */ 319*b4cdae20SChristian Riesch size = (u16) (header & 0x7ff); 320*b4cdae20SChristian Riesch if (size != ((~header >> 16) & 0x07ff)) { 321*b4cdae20SChristian Riesch netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); 322*b4cdae20SChristian Riesch return 0; 323*b4cdae20SChristian Riesch } 324*b4cdae20SChristian Riesch 325*b4cdae20SChristian Riesch if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || 326*b4cdae20SChristian Riesch (size + offset > skb->len)) { 327*b4cdae20SChristian Riesch netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", 328*b4cdae20SChristian Riesch size); 329*b4cdae20SChristian Riesch return 0; 330*b4cdae20SChristian Riesch } 331*b4cdae20SChristian Riesch ax_skb = netdev_alloc_skb_ip_align(dev->net, size); 332*b4cdae20SChristian Riesch if (!ax_skb) 333*b4cdae20SChristian Riesch return 0; 334*b4cdae20SChristian Riesch 335*b4cdae20SChristian Riesch skb_put(ax_skb, size); 336*b4cdae20SChristian Riesch memcpy(ax_skb->data, skb->data + offset, size); 337*b4cdae20SChristian Riesch usbnet_skb_return(dev, ax_skb); 338*b4cdae20SChristian Riesch 339*b4cdae20SChristian Riesch offset += (size + 1) & 0xfffe; 340*b4cdae20SChristian Riesch } 341*b4cdae20SChristian Riesch 342*b4cdae20SChristian Riesch if (skb->len != offset) { 343*b4cdae20SChristian Riesch netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", 344*b4cdae20SChristian Riesch skb->len); 345*b4cdae20SChristian Riesch return 0; 346*b4cdae20SChristian Riesch } 347*b4cdae20SChristian Riesch return 1; 348*b4cdae20SChristian Riesch } 349*b4cdae20SChristian Riesch 350*b4cdae20SChristian Riesch static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 351*b4cdae20SChristian Riesch gfp_t flags) 352*b4cdae20SChristian Riesch { 353*b4cdae20SChristian Riesch int padlen; 354*b4cdae20SChristian Riesch int headroom = skb_headroom(skb); 355*b4cdae20SChristian Riesch int tailroom = skb_tailroom(skb); 356*b4cdae20SChristian Riesch u32 packet_len; 357*b4cdae20SChristian Riesch u32 padbytes = 0xffff0000; 358*b4cdae20SChristian Riesch 359*b4cdae20SChristian Riesch padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; 360*b4cdae20SChristian Riesch 361*b4cdae20SChristian Riesch /* We need to push 4 bytes in front of frame (packet_len) 362*b4cdae20SChristian Riesch * and maybe add 4 bytes after the end (if padlen is 4) 363*b4cdae20SChristian Riesch * 364*b4cdae20SChristian Riesch * Avoid skb_copy_expand() expensive call, using following rules : 365*b4cdae20SChristian Riesch * - We are allowed to push 4 bytes in headroom if skb_header_cloned() 366*b4cdae20SChristian Riesch * is false (and if we have 4 bytes of headroom) 367*b4cdae20SChristian Riesch * - We are allowed to put 4 bytes at tail if skb_cloned() 368*b4cdae20SChristian Riesch * is false (and if we have 4 bytes of tailroom) 369*b4cdae20SChristian Riesch * 370*b4cdae20SChristian Riesch * TCP packets for example are cloned, but skb_header_release() 371*b4cdae20SChristian Riesch * was called in tcp stack, allowing us to use headroom for our needs. 372*b4cdae20SChristian Riesch */ 373*b4cdae20SChristian Riesch if (!skb_header_cloned(skb) && 374*b4cdae20SChristian Riesch !(padlen && skb_cloned(skb)) && 375*b4cdae20SChristian Riesch headroom + tailroom >= 4 + padlen) { 376*b4cdae20SChristian Riesch /* following should not happen, but better be safe */ 377*b4cdae20SChristian Riesch if (headroom < 4 || 378*b4cdae20SChristian Riesch tailroom < padlen) { 379*b4cdae20SChristian Riesch skb->data = memmove(skb->head + 4, skb->data, skb->len); 380*b4cdae20SChristian Riesch skb_set_tail_pointer(skb, skb->len); 381*b4cdae20SChristian Riesch } 382*b4cdae20SChristian Riesch } else { 383*b4cdae20SChristian Riesch struct sk_buff *skb2; 384*b4cdae20SChristian Riesch 385*b4cdae20SChristian Riesch skb2 = skb_copy_expand(skb, 4, padlen, flags); 386*b4cdae20SChristian Riesch dev_kfree_skb_any(skb); 387*b4cdae20SChristian Riesch skb = skb2; 388*b4cdae20SChristian Riesch if (!skb) 389*b4cdae20SChristian Riesch return NULL; 390*b4cdae20SChristian Riesch } 391*b4cdae20SChristian Riesch 392*b4cdae20SChristian Riesch packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; 393*b4cdae20SChristian Riesch skb_push(skb, 4); 394*b4cdae20SChristian Riesch cpu_to_le32s(&packet_len); 395*b4cdae20SChristian Riesch skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); 396*b4cdae20SChristian Riesch 397*b4cdae20SChristian Riesch if (padlen) { 398*b4cdae20SChristian Riesch cpu_to_le32s(&padbytes); 399*b4cdae20SChristian Riesch memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); 400*b4cdae20SChristian Riesch skb_put(skb, sizeof(padbytes)); 401*b4cdae20SChristian Riesch } 402*b4cdae20SChristian Riesch return skb; 403*b4cdae20SChristian Riesch } 404*b4cdae20SChristian Riesch 405*b4cdae20SChristian Riesch static void asix_status(struct usbnet *dev, struct urb *urb) 406*b4cdae20SChristian Riesch { 407*b4cdae20SChristian Riesch struct ax88172_int_data *event; 408*b4cdae20SChristian Riesch int link; 409*b4cdae20SChristian Riesch 410*b4cdae20SChristian Riesch if (urb->actual_length < 8) 411*b4cdae20SChristian Riesch return; 412*b4cdae20SChristian Riesch 413*b4cdae20SChristian Riesch event = urb->transfer_buffer; 414*b4cdae20SChristian Riesch link = event->link & 0x01; 415*b4cdae20SChristian Riesch if (netif_carrier_ok(dev->net) != link) { 416*b4cdae20SChristian Riesch if (link) { 417*b4cdae20SChristian Riesch netif_carrier_on(dev->net); 418*b4cdae20SChristian Riesch usbnet_defer_kevent (dev, EVENT_LINK_RESET ); 419*b4cdae20SChristian Riesch } else 420*b4cdae20SChristian Riesch netif_carrier_off(dev->net); 421*b4cdae20SChristian Riesch netdev_dbg(dev->net, "Link Status is: %d\n", link); 422*b4cdae20SChristian Riesch } 423*b4cdae20SChristian Riesch } 424*b4cdae20SChristian Riesch 425*b4cdae20SChristian Riesch static inline int asix_set_sw_mii(struct usbnet *dev) 426*b4cdae20SChristian Riesch { 427*b4cdae20SChristian Riesch int ret; 428*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); 429*b4cdae20SChristian Riesch if (ret < 0) 430*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to enable software MII access\n"); 431*b4cdae20SChristian Riesch return ret; 432*b4cdae20SChristian Riesch } 433*b4cdae20SChristian Riesch 434*b4cdae20SChristian Riesch static inline int asix_set_hw_mii(struct usbnet *dev) 435*b4cdae20SChristian Riesch { 436*b4cdae20SChristian Riesch int ret; 437*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); 438*b4cdae20SChristian Riesch if (ret < 0) 439*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to enable hardware MII access\n"); 440*b4cdae20SChristian Riesch return ret; 441*b4cdae20SChristian Riesch } 442*b4cdae20SChristian Riesch 443*b4cdae20SChristian Riesch static inline int asix_get_phy_addr(struct usbnet *dev) 444*b4cdae20SChristian Riesch { 445*b4cdae20SChristian Riesch u8 buf[2]; 446*b4cdae20SChristian Riesch int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); 447*b4cdae20SChristian Riesch 448*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_get_phy_addr()\n"); 449*b4cdae20SChristian Riesch 450*b4cdae20SChristian Riesch if (ret < 0) { 451*b4cdae20SChristian Riesch netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); 452*b4cdae20SChristian Riesch goto out; 453*b4cdae20SChristian Riesch } 454*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", 455*b4cdae20SChristian Riesch *((__le16 *)buf)); 456*b4cdae20SChristian Riesch ret = buf[1]; 457*b4cdae20SChristian Riesch 458*b4cdae20SChristian Riesch out: 459*b4cdae20SChristian Riesch return ret; 460*b4cdae20SChristian Riesch } 461*b4cdae20SChristian Riesch 462*b4cdae20SChristian Riesch static int asix_sw_reset(struct usbnet *dev, u8 flags) 463*b4cdae20SChristian Riesch { 464*b4cdae20SChristian Riesch int ret; 465*b4cdae20SChristian Riesch 466*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); 467*b4cdae20SChristian Riesch if (ret < 0) 468*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); 469*b4cdae20SChristian Riesch 470*b4cdae20SChristian Riesch return ret; 471*b4cdae20SChristian Riesch } 472*b4cdae20SChristian Riesch 473*b4cdae20SChristian Riesch static u16 asix_read_rx_ctl(struct usbnet *dev) 474*b4cdae20SChristian Riesch { 475*b4cdae20SChristian Riesch __le16 v; 476*b4cdae20SChristian Riesch int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); 477*b4cdae20SChristian Riesch 478*b4cdae20SChristian Riesch if (ret < 0) { 479*b4cdae20SChristian Riesch netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); 480*b4cdae20SChristian Riesch goto out; 481*b4cdae20SChristian Riesch } 482*b4cdae20SChristian Riesch ret = le16_to_cpu(v); 483*b4cdae20SChristian Riesch out: 484*b4cdae20SChristian Riesch return ret; 485*b4cdae20SChristian Riesch } 486*b4cdae20SChristian Riesch 487*b4cdae20SChristian Riesch static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) 488*b4cdae20SChristian Riesch { 489*b4cdae20SChristian Riesch int ret; 490*b4cdae20SChristian Riesch 491*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); 492*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); 493*b4cdae20SChristian Riesch if (ret < 0) 494*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", 495*b4cdae20SChristian Riesch mode, ret); 496*b4cdae20SChristian Riesch 497*b4cdae20SChristian Riesch return ret; 498*b4cdae20SChristian Riesch } 499*b4cdae20SChristian Riesch 500*b4cdae20SChristian Riesch static u16 asix_read_medium_status(struct usbnet *dev) 501*b4cdae20SChristian Riesch { 502*b4cdae20SChristian Riesch __le16 v; 503*b4cdae20SChristian Riesch int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); 504*b4cdae20SChristian Riesch 505*b4cdae20SChristian Riesch if (ret < 0) { 506*b4cdae20SChristian Riesch netdev_err(dev->net, "Error reading Medium Status register: %02x\n", 507*b4cdae20SChristian Riesch ret); 508*b4cdae20SChristian Riesch return ret; /* TODO: callers not checking for error ret */ 509*b4cdae20SChristian Riesch } 510*b4cdae20SChristian Riesch 511*b4cdae20SChristian Riesch return le16_to_cpu(v); 512*b4cdae20SChristian Riesch 513*b4cdae20SChristian Riesch } 514*b4cdae20SChristian Riesch 515*b4cdae20SChristian Riesch static int asix_write_medium_mode(struct usbnet *dev, u16 mode) 516*b4cdae20SChristian Riesch { 517*b4cdae20SChristian Riesch int ret; 518*b4cdae20SChristian Riesch 519*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); 520*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); 521*b4cdae20SChristian Riesch if (ret < 0) 522*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", 523*b4cdae20SChristian Riesch mode, ret); 524*b4cdae20SChristian Riesch 525*b4cdae20SChristian Riesch return ret; 526*b4cdae20SChristian Riesch } 527*b4cdae20SChristian Riesch 528*b4cdae20SChristian Riesch static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) 529*b4cdae20SChristian Riesch { 530*b4cdae20SChristian Riesch int ret; 531*b4cdae20SChristian Riesch 532*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); 533*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); 534*b4cdae20SChristian Riesch if (ret < 0) 535*b4cdae20SChristian Riesch netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", 536*b4cdae20SChristian Riesch value, ret); 537*b4cdae20SChristian Riesch 538*b4cdae20SChristian Riesch if (sleep) 539*b4cdae20SChristian Riesch msleep(sleep); 540*b4cdae20SChristian Riesch 541*b4cdae20SChristian Riesch return ret; 542*b4cdae20SChristian Riesch } 543*b4cdae20SChristian Riesch 544*b4cdae20SChristian Riesch /* 545*b4cdae20SChristian Riesch * AX88772 & AX88178 have a 16-bit RX_CTL value 546*b4cdae20SChristian Riesch */ 547*b4cdae20SChristian Riesch static void asix_set_multicast(struct net_device *net) 548*b4cdae20SChristian Riesch { 549*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 550*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 551*b4cdae20SChristian Riesch u16 rx_ctl = AX_DEFAULT_RX_CTL; 552*b4cdae20SChristian Riesch 553*b4cdae20SChristian Riesch if (net->flags & IFF_PROMISC) { 554*b4cdae20SChristian Riesch rx_ctl |= AX_RX_CTL_PRO; 555*b4cdae20SChristian Riesch } else if (net->flags & IFF_ALLMULTI || 556*b4cdae20SChristian Riesch netdev_mc_count(net) > AX_MAX_MCAST) { 557*b4cdae20SChristian Riesch rx_ctl |= AX_RX_CTL_AMALL; 558*b4cdae20SChristian Riesch } else if (netdev_mc_empty(net)) { 559*b4cdae20SChristian Riesch /* just broadcast and directed */ 560*b4cdae20SChristian Riesch } else { 561*b4cdae20SChristian Riesch /* We use the 20 byte dev->data 562*b4cdae20SChristian Riesch * for our 8 byte filter buffer 563*b4cdae20SChristian Riesch * to avoid allocating memory that 564*b4cdae20SChristian Riesch * is tricky to free later */ 565*b4cdae20SChristian Riesch struct netdev_hw_addr *ha; 566*b4cdae20SChristian Riesch u32 crc_bits; 567*b4cdae20SChristian Riesch 568*b4cdae20SChristian Riesch memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); 569*b4cdae20SChristian Riesch 570*b4cdae20SChristian Riesch /* Build the multicast hash filter. */ 571*b4cdae20SChristian Riesch netdev_for_each_mc_addr(ha, net) { 572*b4cdae20SChristian Riesch crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 573*b4cdae20SChristian Riesch data->multi_filter[crc_bits >> 3] |= 574*b4cdae20SChristian Riesch 1 << (crc_bits & 7); 575*b4cdae20SChristian Riesch } 576*b4cdae20SChristian Riesch 577*b4cdae20SChristian Riesch asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, 578*b4cdae20SChristian Riesch AX_MCAST_FILTER_SIZE, data->multi_filter); 579*b4cdae20SChristian Riesch 580*b4cdae20SChristian Riesch rx_ctl |= AX_RX_CTL_AM; 581*b4cdae20SChristian Riesch } 582*b4cdae20SChristian Riesch 583*b4cdae20SChristian Riesch asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); 584*b4cdae20SChristian Riesch } 585*b4cdae20SChristian Riesch 586*b4cdae20SChristian Riesch static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) 587*b4cdae20SChristian Riesch { 588*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(netdev); 589*b4cdae20SChristian Riesch __le16 res; 590*b4cdae20SChristian Riesch 591*b4cdae20SChristian Riesch mutex_lock(&dev->phy_mutex); 592*b4cdae20SChristian Riesch asix_set_sw_mii(dev); 593*b4cdae20SChristian Riesch asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, 594*b4cdae20SChristian Riesch (__u16)loc, 2, &res); 595*b4cdae20SChristian Riesch asix_set_hw_mii(dev); 596*b4cdae20SChristian Riesch mutex_unlock(&dev->phy_mutex); 597*b4cdae20SChristian Riesch 598*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 599*b4cdae20SChristian Riesch phy_id, loc, le16_to_cpu(res)); 600*b4cdae20SChristian Riesch 601*b4cdae20SChristian Riesch return le16_to_cpu(res); 602*b4cdae20SChristian Riesch } 603*b4cdae20SChristian Riesch 604*b4cdae20SChristian Riesch static void 605*b4cdae20SChristian Riesch asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) 606*b4cdae20SChristian Riesch { 607*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(netdev); 608*b4cdae20SChristian Riesch __le16 res = cpu_to_le16(val); 609*b4cdae20SChristian Riesch 610*b4cdae20SChristian Riesch netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 611*b4cdae20SChristian Riesch phy_id, loc, val); 612*b4cdae20SChristian Riesch mutex_lock(&dev->phy_mutex); 613*b4cdae20SChristian Riesch asix_set_sw_mii(dev); 614*b4cdae20SChristian Riesch asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); 615*b4cdae20SChristian Riesch asix_set_hw_mii(dev); 616*b4cdae20SChristian Riesch mutex_unlock(&dev->phy_mutex); 617*b4cdae20SChristian Riesch } 618*b4cdae20SChristian Riesch 619*b4cdae20SChristian Riesch /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ 620*b4cdae20SChristian Riesch static u32 asix_get_phyid(struct usbnet *dev) 621*b4cdae20SChristian Riesch { 622*b4cdae20SChristian Riesch int phy_reg; 623*b4cdae20SChristian Riesch u32 phy_id; 624*b4cdae20SChristian Riesch int i; 625*b4cdae20SChristian Riesch 626*b4cdae20SChristian Riesch /* Poll for the rare case the FW or phy isn't ready yet. */ 627*b4cdae20SChristian Riesch for (i = 0; i < 100; i++) { 628*b4cdae20SChristian Riesch phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); 629*b4cdae20SChristian Riesch if (phy_reg != 0 && phy_reg != 0xFFFF) 630*b4cdae20SChristian Riesch break; 631*b4cdae20SChristian Riesch mdelay(1); 632*b4cdae20SChristian Riesch } 633*b4cdae20SChristian Riesch 634*b4cdae20SChristian Riesch if (phy_reg <= 0 || phy_reg == 0xFFFF) 635*b4cdae20SChristian Riesch return 0; 636*b4cdae20SChristian Riesch 637*b4cdae20SChristian Riesch phy_id = (phy_reg & 0xffff) << 16; 638*b4cdae20SChristian Riesch 639*b4cdae20SChristian Riesch phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); 640*b4cdae20SChristian Riesch if (phy_reg < 0) 641*b4cdae20SChristian Riesch return 0; 642*b4cdae20SChristian Riesch 643*b4cdae20SChristian Riesch phy_id |= (phy_reg & 0xffff); 644*b4cdae20SChristian Riesch 645*b4cdae20SChristian Riesch return phy_id; 646*b4cdae20SChristian Riesch } 647*b4cdae20SChristian Riesch 648*b4cdae20SChristian Riesch static void 649*b4cdae20SChristian Riesch asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) 650*b4cdae20SChristian Riesch { 651*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 652*b4cdae20SChristian Riesch u8 opt; 653*b4cdae20SChristian Riesch 654*b4cdae20SChristian Riesch if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { 655*b4cdae20SChristian Riesch wolinfo->supported = 0; 656*b4cdae20SChristian Riesch wolinfo->wolopts = 0; 657*b4cdae20SChristian Riesch return; 658*b4cdae20SChristian Riesch } 659*b4cdae20SChristian Riesch wolinfo->supported = WAKE_PHY | WAKE_MAGIC; 660*b4cdae20SChristian Riesch wolinfo->wolopts = 0; 661*b4cdae20SChristian Riesch if (opt & AX_MONITOR_LINK) 662*b4cdae20SChristian Riesch wolinfo->wolopts |= WAKE_PHY; 663*b4cdae20SChristian Riesch if (opt & AX_MONITOR_MAGIC) 664*b4cdae20SChristian Riesch wolinfo->wolopts |= WAKE_MAGIC; 665*b4cdae20SChristian Riesch } 666*b4cdae20SChristian Riesch 667*b4cdae20SChristian Riesch static int 668*b4cdae20SChristian Riesch asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) 669*b4cdae20SChristian Riesch { 670*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 671*b4cdae20SChristian Riesch u8 opt = 0; 672*b4cdae20SChristian Riesch 673*b4cdae20SChristian Riesch if (wolinfo->wolopts & WAKE_PHY) 674*b4cdae20SChristian Riesch opt |= AX_MONITOR_LINK; 675*b4cdae20SChristian Riesch if (wolinfo->wolopts & WAKE_MAGIC) 676*b4cdae20SChristian Riesch opt |= AX_MONITOR_MAGIC; 677*b4cdae20SChristian Riesch 678*b4cdae20SChristian Riesch if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, 679*b4cdae20SChristian Riesch opt, 0, 0, NULL) < 0) 680*b4cdae20SChristian Riesch return -EINVAL; 681*b4cdae20SChristian Riesch 682*b4cdae20SChristian Riesch return 0; 683*b4cdae20SChristian Riesch } 684*b4cdae20SChristian Riesch 685*b4cdae20SChristian Riesch static int asix_get_eeprom_len(struct net_device *net) 686*b4cdae20SChristian Riesch { 687*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 688*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 689*b4cdae20SChristian Riesch 690*b4cdae20SChristian Riesch return data->eeprom_len; 691*b4cdae20SChristian Riesch } 692*b4cdae20SChristian Riesch 693*b4cdae20SChristian Riesch static int asix_get_eeprom(struct net_device *net, 694*b4cdae20SChristian Riesch struct ethtool_eeprom *eeprom, u8 *data) 695*b4cdae20SChristian Riesch { 696*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 697*b4cdae20SChristian Riesch __le16 *ebuf = (__le16 *)data; 698*b4cdae20SChristian Riesch int i; 699*b4cdae20SChristian Riesch 700*b4cdae20SChristian Riesch /* Crude hack to ensure that we don't overwrite memory 701*b4cdae20SChristian Riesch * if an odd length is supplied 702*b4cdae20SChristian Riesch */ 703*b4cdae20SChristian Riesch if (eeprom->len % 2) 704*b4cdae20SChristian Riesch return -EINVAL; 705*b4cdae20SChristian Riesch 706*b4cdae20SChristian Riesch eeprom->magic = AX_EEPROM_MAGIC; 707*b4cdae20SChristian Riesch 708*b4cdae20SChristian Riesch /* ax8817x returns 2 bytes from eeprom on read */ 709*b4cdae20SChristian Riesch for (i=0; i < eeprom->len / 2; i++) { 710*b4cdae20SChristian Riesch if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, 711*b4cdae20SChristian Riesch eeprom->offset + i, 0, 2, &ebuf[i]) < 0) 712*b4cdae20SChristian Riesch return -EINVAL; 713*b4cdae20SChristian Riesch } 714*b4cdae20SChristian Riesch return 0; 715*b4cdae20SChristian Riesch } 716*b4cdae20SChristian Riesch 717*b4cdae20SChristian Riesch static void asix_get_drvinfo (struct net_device *net, 718*b4cdae20SChristian Riesch struct ethtool_drvinfo *info) 719*b4cdae20SChristian Riesch { 720*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 721*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 722*b4cdae20SChristian Riesch 723*b4cdae20SChristian Riesch /* Inherit standard device info */ 724*b4cdae20SChristian Riesch usbnet_get_drvinfo(net, info); 725*b4cdae20SChristian Riesch strncpy (info->driver, DRIVER_NAME, sizeof info->driver); 726*b4cdae20SChristian Riesch strncpy (info->version, DRIVER_VERSION, sizeof info->version); 727*b4cdae20SChristian Riesch info->eedump_len = data->eeprom_len; 728*b4cdae20SChristian Riesch } 729*b4cdae20SChristian Riesch 730*b4cdae20SChristian Riesch static u32 asix_get_link(struct net_device *net) 731*b4cdae20SChristian Riesch { 732*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 733*b4cdae20SChristian Riesch 734*b4cdae20SChristian Riesch return mii_link_ok(&dev->mii); 735*b4cdae20SChristian Riesch } 736*b4cdae20SChristian Riesch 737*b4cdae20SChristian Riesch static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) 738*b4cdae20SChristian Riesch { 739*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 740*b4cdae20SChristian Riesch 741*b4cdae20SChristian Riesch return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); 742*b4cdae20SChristian Riesch } 743*b4cdae20SChristian Riesch 744*b4cdae20SChristian Riesch static int asix_set_mac_address(struct net_device *net, void *p) 745*b4cdae20SChristian Riesch { 746*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 747*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 748*b4cdae20SChristian Riesch struct sockaddr *addr = p; 749*b4cdae20SChristian Riesch 750*b4cdae20SChristian Riesch if (netif_running(net)) 751*b4cdae20SChristian Riesch return -EBUSY; 752*b4cdae20SChristian Riesch if (!is_valid_ether_addr(addr->sa_data)) 753*b4cdae20SChristian Riesch return -EADDRNOTAVAIL; 754*b4cdae20SChristian Riesch 755*b4cdae20SChristian Riesch memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); 756*b4cdae20SChristian Riesch 757*b4cdae20SChristian Riesch /* We use the 20 byte dev->data 758*b4cdae20SChristian Riesch * for our 6 byte mac buffer 759*b4cdae20SChristian Riesch * to avoid allocating memory that 760*b4cdae20SChristian Riesch * is tricky to free later */ 761*b4cdae20SChristian Riesch memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); 762*b4cdae20SChristian Riesch asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 763*b4cdae20SChristian Riesch data->mac_addr); 764*b4cdae20SChristian Riesch 765*b4cdae20SChristian Riesch return 0; 766*b4cdae20SChristian Riesch } 767*b4cdae20SChristian Riesch 768*b4cdae20SChristian Riesch /* We need to override some ethtool_ops so we require our 769*b4cdae20SChristian Riesch own structure so we don't interfere with other usbnet 770*b4cdae20SChristian Riesch devices that may be connected at the same time. */ 771*b4cdae20SChristian Riesch static const struct ethtool_ops ax88172_ethtool_ops = { 772*b4cdae20SChristian Riesch .get_drvinfo = asix_get_drvinfo, 773*b4cdae20SChristian Riesch .get_link = asix_get_link, 774*b4cdae20SChristian Riesch .get_msglevel = usbnet_get_msglevel, 775*b4cdae20SChristian Riesch .set_msglevel = usbnet_set_msglevel, 776*b4cdae20SChristian Riesch .get_wol = asix_get_wol, 777*b4cdae20SChristian Riesch .set_wol = asix_set_wol, 778*b4cdae20SChristian Riesch .get_eeprom_len = asix_get_eeprom_len, 779*b4cdae20SChristian Riesch .get_eeprom = asix_get_eeprom, 780*b4cdae20SChristian Riesch .get_settings = usbnet_get_settings, 781*b4cdae20SChristian Riesch .set_settings = usbnet_set_settings, 782*b4cdae20SChristian Riesch .nway_reset = usbnet_nway_reset, 783*b4cdae20SChristian Riesch }; 784*b4cdae20SChristian Riesch 785*b4cdae20SChristian Riesch static void ax88172_set_multicast(struct net_device *net) 786*b4cdae20SChristian Riesch { 787*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 788*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 789*b4cdae20SChristian Riesch u8 rx_ctl = 0x8c; 790*b4cdae20SChristian Riesch 791*b4cdae20SChristian Riesch if (net->flags & IFF_PROMISC) { 792*b4cdae20SChristian Riesch rx_ctl |= 0x01; 793*b4cdae20SChristian Riesch } else if (net->flags & IFF_ALLMULTI || 794*b4cdae20SChristian Riesch netdev_mc_count(net) > AX_MAX_MCAST) { 795*b4cdae20SChristian Riesch rx_ctl |= 0x02; 796*b4cdae20SChristian Riesch } else if (netdev_mc_empty(net)) { 797*b4cdae20SChristian Riesch /* just broadcast and directed */ 798*b4cdae20SChristian Riesch } else { 799*b4cdae20SChristian Riesch /* We use the 20 byte dev->data 800*b4cdae20SChristian Riesch * for our 8 byte filter buffer 801*b4cdae20SChristian Riesch * to avoid allocating memory that 802*b4cdae20SChristian Riesch * is tricky to free later */ 803*b4cdae20SChristian Riesch struct netdev_hw_addr *ha; 804*b4cdae20SChristian Riesch u32 crc_bits; 805*b4cdae20SChristian Riesch 806*b4cdae20SChristian Riesch memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); 807*b4cdae20SChristian Riesch 808*b4cdae20SChristian Riesch /* Build the multicast hash filter. */ 809*b4cdae20SChristian Riesch netdev_for_each_mc_addr(ha, net) { 810*b4cdae20SChristian Riesch crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 811*b4cdae20SChristian Riesch data->multi_filter[crc_bits >> 3] |= 812*b4cdae20SChristian Riesch 1 << (crc_bits & 7); 813*b4cdae20SChristian Riesch } 814*b4cdae20SChristian Riesch 815*b4cdae20SChristian Riesch asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, 816*b4cdae20SChristian Riesch AX_MCAST_FILTER_SIZE, data->multi_filter); 817*b4cdae20SChristian Riesch 818*b4cdae20SChristian Riesch rx_ctl |= 0x10; 819*b4cdae20SChristian Riesch } 820*b4cdae20SChristian Riesch 821*b4cdae20SChristian Riesch asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); 822*b4cdae20SChristian Riesch } 823*b4cdae20SChristian Riesch 824*b4cdae20SChristian Riesch static int ax88172_link_reset(struct usbnet *dev) 825*b4cdae20SChristian Riesch { 826*b4cdae20SChristian Riesch u8 mode; 827*b4cdae20SChristian Riesch struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 828*b4cdae20SChristian Riesch 829*b4cdae20SChristian Riesch mii_check_media(&dev->mii, 1, 1); 830*b4cdae20SChristian Riesch mii_ethtool_gset(&dev->mii, &ecmd); 831*b4cdae20SChristian Riesch mode = AX88172_MEDIUM_DEFAULT; 832*b4cdae20SChristian Riesch 833*b4cdae20SChristian Riesch if (ecmd.duplex != DUPLEX_FULL) 834*b4cdae20SChristian Riesch mode |= ~AX88172_MEDIUM_FD; 835*b4cdae20SChristian Riesch 836*b4cdae20SChristian Riesch netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 837*b4cdae20SChristian Riesch ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 838*b4cdae20SChristian Riesch 839*b4cdae20SChristian Riesch asix_write_medium_mode(dev, mode); 840*b4cdae20SChristian Riesch 841*b4cdae20SChristian Riesch return 0; 842*b4cdae20SChristian Riesch } 843*b4cdae20SChristian Riesch 844*b4cdae20SChristian Riesch static const struct net_device_ops ax88172_netdev_ops = { 845*b4cdae20SChristian Riesch .ndo_open = usbnet_open, 846*b4cdae20SChristian Riesch .ndo_stop = usbnet_stop, 847*b4cdae20SChristian Riesch .ndo_start_xmit = usbnet_start_xmit, 848*b4cdae20SChristian Riesch .ndo_tx_timeout = usbnet_tx_timeout, 849*b4cdae20SChristian Riesch .ndo_change_mtu = usbnet_change_mtu, 850*b4cdae20SChristian Riesch .ndo_set_mac_address = eth_mac_addr, 851*b4cdae20SChristian Riesch .ndo_validate_addr = eth_validate_addr, 852*b4cdae20SChristian Riesch .ndo_do_ioctl = asix_ioctl, 853*b4cdae20SChristian Riesch .ndo_set_rx_mode = ax88172_set_multicast, 854*b4cdae20SChristian Riesch }; 855*b4cdae20SChristian Riesch 856*b4cdae20SChristian Riesch static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) 857*b4cdae20SChristian Riesch { 858*b4cdae20SChristian Riesch int ret = 0; 859*b4cdae20SChristian Riesch u8 buf[ETH_ALEN]; 860*b4cdae20SChristian Riesch int i; 861*b4cdae20SChristian Riesch unsigned long gpio_bits = dev->driver_info->data; 862*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 863*b4cdae20SChristian Riesch 864*b4cdae20SChristian Riesch data->eeprom_len = AX88172_EEPROM_LEN; 865*b4cdae20SChristian Riesch 866*b4cdae20SChristian Riesch usbnet_get_endpoints(dev,intf); 867*b4cdae20SChristian Riesch 868*b4cdae20SChristian Riesch /* Toggle the GPIOs in a manufacturer/model specific way */ 869*b4cdae20SChristian Riesch for (i = 2; i >= 0; i--) { 870*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, 871*b4cdae20SChristian Riesch (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); 872*b4cdae20SChristian Riesch if (ret < 0) 873*b4cdae20SChristian Riesch goto out; 874*b4cdae20SChristian Riesch msleep(5); 875*b4cdae20SChristian Riesch } 876*b4cdae20SChristian Riesch 877*b4cdae20SChristian Riesch ret = asix_write_rx_ctl(dev, 0x80); 878*b4cdae20SChristian Riesch if (ret < 0) 879*b4cdae20SChristian Riesch goto out; 880*b4cdae20SChristian Riesch 881*b4cdae20SChristian Riesch /* Get the MAC address */ 882*b4cdae20SChristian Riesch ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 883*b4cdae20SChristian Riesch if (ret < 0) { 884*b4cdae20SChristian Riesch dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); 885*b4cdae20SChristian Riesch goto out; 886*b4cdae20SChristian Riesch } 887*b4cdae20SChristian Riesch memcpy(dev->net->dev_addr, buf, ETH_ALEN); 888*b4cdae20SChristian Riesch 889*b4cdae20SChristian Riesch /* Initialize MII structure */ 890*b4cdae20SChristian Riesch dev->mii.dev = dev->net; 891*b4cdae20SChristian Riesch dev->mii.mdio_read = asix_mdio_read; 892*b4cdae20SChristian Riesch dev->mii.mdio_write = asix_mdio_write; 893*b4cdae20SChristian Riesch dev->mii.phy_id_mask = 0x3f; 894*b4cdae20SChristian Riesch dev->mii.reg_num_mask = 0x1f; 895*b4cdae20SChristian Riesch dev->mii.phy_id = asix_get_phy_addr(dev); 896*b4cdae20SChristian Riesch 897*b4cdae20SChristian Riesch dev->net->netdev_ops = &ax88172_netdev_ops; 898*b4cdae20SChristian Riesch dev->net->ethtool_ops = &ax88172_ethtool_ops; 899*b4cdae20SChristian Riesch dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ 900*b4cdae20SChristian Riesch dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ 901*b4cdae20SChristian Riesch 902*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); 903*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 904*b4cdae20SChristian Riesch ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 905*b4cdae20SChristian Riesch mii_nway_restart(&dev->mii); 906*b4cdae20SChristian Riesch 907*b4cdae20SChristian Riesch return 0; 908*b4cdae20SChristian Riesch 909*b4cdae20SChristian Riesch out: 910*b4cdae20SChristian Riesch return ret; 911*b4cdae20SChristian Riesch } 912*b4cdae20SChristian Riesch 913*b4cdae20SChristian Riesch static const struct ethtool_ops ax88772_ethtool_ops = { 914*b4cdae20SChristian Riesch .get_drvinfo = asix_get_drvinfo, 915*b4cdae20SChristian Riesch .get_link = asix_get_link, 916*b4cdae20SChristian Riesch .get_msglevel = usbnet_get_msglevel, 917*b4cdae20SChristian Riesch .set_msglevel = usbnet_set_msglevel, 918*b4cdae20SChristian Riesch .get_wol = asix_get_wol, 919*b4cdae20SChristian Riesch .set_wol = asix_set_wol, 920*b4cdae20SChristian Riesch .get_eeprom_len = asix_get_eeprom_len, 921*b4cdae20SChristian Riesch .get_eeprom = asix_get_eeprom, 922*b4cdae20SChristian Riesch .get_settings = usbnet_get_settings, 923*b4cdae20SChristian Riesch .set_settings = usbnet_set_settings, 924*b4cdae20SChristian Riesch .nway_reset = usbnet_nway_reset, 925*b4cdae20SChristian Riesch }; 926*b4cdae20SChristian Riesch 927*b4cdae20SChristian Riesch static int ax88772_link_reset(struct usbnet *dev) 928*b4cdae20SChristian Riesch { 929*b4cdae20SChristian Riesch u16 mode; 930*b4cdae20SChristian Riesch struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 931*b4cdae20SChristian Riesch 932*b4cdae20SChristian Riesch mii_check_media(&dev->mii, 1, 1); 933*b4cdae20SChristian Riesch mii_ethtool_gset(&dev->mii, &ecmd); 934*b4cdae20SChristian Riesch mode = AX88772_MEDIUM_DEFAULT; 935*b4cdae20SChristian Riesch 936*b4cdae20SChristian Riesch if (ethtool_cmd_speed(&ecmd) != SPEED_100) 937*b4cdae20SChristian Riesch mode &= ~AX_MEDIUM_PS; 938*b4cdae20SChristian Riesch 939*b4cdae20SChristian Riesch if (ecmd.duplex != DUPLEX_FULL) 940*b4cdae20SChristian Riesch mode &= ~AX_MEDIUM_FD; 941*b4cdae20SChristian Riesch 942*b4cdae20SChristian Riesch netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 943*b4cdae20SChristian Riesch ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 944*b4cdae20SChristian Riesch 945*b4cdae20SChristian Riesch asix_write_medium_mode(dev, mode); 946*b4cdae20SChristian Riesch 947*b4cdae20SChristian Riesch return 0; 948*b4cdae20SChristian Riesch } 949*b4cdae20SChristian Riesch 950*b4cdae20SChristian Riesch static int ax88772_reset(struct usbnet *dev) 951*b4cdae20SChristian Riesch { 952*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 953*b4cdae20SChristian Riesch int ret, embd_phy; 954*b4cdae20SChristian Riesch u16 rx_ctl; 955*b4cdae20SChristian Riesch 956*b4cdae20SChristian Riesch ret = asix_write_gpio(dev, 957*b4cdae20SChristian Riesch AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); 958*b4cdae20SChristian Riesch if (ret < 0) 959*b4cdae20SChristian Riesch goto out; 960*b4cdae20SChristian Riesch 961*b4cdae20SChristian Riesch embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); 962*b4cdae20SChristian Riesch 963*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); 964*b4cdae20SChristian Riesch if (ret < 0) { 965*b4cdae20SChristian Riesch dbg("Select PHY #1 failed: %d", ret); 966*b4cdae20SChristian Riesch goto out; 967*b4cdae20SChristian Riesch } 968*b4cdae20SChristian Riesch 969*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); 970*b4cdae20SChristian Riesch if (ret < 0) 971*b4cdae20SChristian Riesch goto out; 972*b4cdae20SChristian Riesch 973*b4cdae20SChristian Riesch msleep(150); 974*b4cdae20SChristian Riesch 975*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); 976*b4cdae20SChristian Riesch if (ret < 0) 977*b4cdae20SChristian Riesch goto out; 978*b4cdae20SChristian Riesch 979*b4cdae20SChristian Riesch msleep(150); 980*b4cdae20SChristian Riesch 981*b4cdae20SChristian Riesch if (embd_phy) { 982*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_IPRL); 983*b4cdae20SChristian Riesch if (ret < 0) 984*b4cdae20SChristian Riesch goto out; 985*b4cdae20SChristian Riesch } else { 986*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_PRTE); 987*b4cdae20SChristian Riesch if (ret < 0) 988*b4cdae20SChristian Riesch goto out; 989*b4cdae20SChristian Riesch } 990*b4cdae20SChristian Riesch 991*b4cdae20SChristian Riesch msleep(150); 992*b4cdae20SChristian Riesch rx_ctl = asix_read_rx_ctl(dev); 993*b4cdae20SChristian Riesch dbg("RX_CTL is 0x%04x after software reset", rx_ctl); 994*b4cdae20SChristian Riesch ret = asix_write_rx_ctl(dev, 0x0000); 995*b4cdae20SChristian Riesch if (ret < 0) 996*b4cdae20SChristian Riesch goto out; 997*b4cdae20SChristian Riesch 998*b4cdae20SChristian Riesch rx_ctl = asix_read_rx_ctl(dev); 999*b4cdae20SChristian Riesch dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); 1000*b4cdae20SChristian Riesch 1001*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_PRL); 1002*b4cdae20SChristian Riesch if (ret < 0) 1003*b4cdae20SChristian Riesch goto out; 1004*b4cdae20SChristian Riesch 1005*b4cdae20SChristian Riesch msleep(150); 1006*b4cdae20SChristian Riesch 1007*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); 1008*b4cdae20SChristian Riesch if (ret < 0) 1009*b4cdae20SChristian Riesch goto out; 1010*b4cdae20SChristian Riesch 1011*b4cdae20SChristian Riesch msleep(150); 1012*b4cdae20SChristian Riesch 1013*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); 1014*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 1015*b4cdae20SChristian Riesch ADVERTISE_ALL | ADVERTISE_CSMA); 1016*b4cdae20SChristian Riesch mii_nway_restart(&dev->mii); 1017*b4cdae20SChristian Riesch 1018*b4cdae20SChristian Riesch ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); 1019*b4cdae20SChristian Riesch if (ret < 0) 1020*b4cdae20SChristian Riesch goto out; 1021*b4cdae20SChristian Riesch 1022*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, 1023*b4cdae20SChristian Riesch AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, 1024*b4cdae20SChristian Riesch AX88772_IPG2_DEFAULT, 0, NULL); 1025*b4cdae20SChristian Riesch if (ret < 0) { 1026*b4cdae20SChristian Riesch dbg("Write IPG,IPG1,IPG2 failed: %d", ret); 1027*b4cdae20SChristian Riesch goto out; 1028*b4cdae20SChristian Riesch } 1029*b4cdae20SChristian Riesch 1030*b4cdae20SChristian Riesch /* Rewrite MAC address */ 1031*b4cdae20SChristian Riesch memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 1032*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 1033*b4cdae20SChristian Riesch data->mac_addr); 1034*b4cdae20SChristian Riesch if (ret < 0) 1035*b4cdae20SChristian Riesch goto out; 1036*b4cdae20SChristian Riesch 1037*b4cdae20SChristian Riesch /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 1038*b4cdae20SChristian Riesch ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); 1039*b4cdae20SChristian Riesch if (ret < 0) 1040*b4cdae20SChristian Riesch goto out; 1041*b4cdae20SChristian Riesch 1042*b4cdae20SChristian Riesch rx_ctl = asix_read_rx_ctl(dev); 1043*b4cdae20SChristian Riesch dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); 1044*b4cdae20SChristian Riesch 1045*b4cdae20SChristian Riesch rx_ctl = asix_read_medium_status(dev); 1046*b4cdae20SChristian Riesch dbg("Medium Status is 0x%04x after all initializations", rx_ctl); 1047*b4cdae20SChristian Riesch 1048*b4cdae20SChristian Riesch return 0; 1049*b4cdae20SChristian Riesch 1050*b4cdae20SChristian Riesch out: 1051*b4cdae20SChristian Riesch return ret; 1052*b4cdae20SChristian Riesch 1053*b4cdae20SChristian Riesch } 1054*b4cdae20SChristian Riesch 1055*b4cdae20SChristian Riesch static const struct net_device_ops ax88772_netdev_ops = { 1056*b4cdae20SChristian Riesch .ndo_open = usbnet_open, 1057*b4cdae20SChristian Riesch .ndo_stop = usbnet_stop, 1058*b4cdae20SChristian Riesch .ndo_start_xmit = usbnet_start_xmit, 1059*b4cdae20SChristian Riesch .ndo_tx_timeout = usbnet_tx_timeout, 1060*b4cdae20SChristian Riesch .ndo_change_mtu = usbnet_change_mtu, 1061*b4cdae20SChristian Riesch .ndo_set_mac_address = asix_set_mac_address, 1062*b4cdae20SChristian Riesch .ndo_validate_addr = eth_validate_addr, 1063*b4cdae20SChristian Riesch .ndo_do_ioctl = asix_ioctl, 1064*b4cdae20SChristian Riesch .ndo_set_rx_mode = asix_set_multicast, 1065*b4cdae20SChristian Riesch }; 1066*b4cdae20SChristian Riesch 1067*b4cdae20SChristian Riesch static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) 1068*b4cdae20SChristian Riesch { 1069*b4cdae20SChristian Riesch int ret, embd_phy; 1070*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1071*b4cdae20SChristian Riesch u8 buf[ETH_ALEN]; 1072*b4cdae20SChristian Riesch u32 phyid; 1073*b4cdae20SChristian Riesch 1074*b4cdae20SChristian Riesch data->eeprom_len = AX88772_EEPROM_LEN; 1075*b4cdae20SChristian Riesch 1076*b4cdae20SChristian Riesch usbnet_get_endpoints(dev,intf); 1077*b4cdae20SChristian Riesch 1078*b4cdae20SChristian Riesch /* Get the MAC address */ 1079*b4cdae20SChristian Riesch ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 1080*b4cdae20SChristian Riesch if (ret < 0) { 1081*b4cdae20SChristian Riesch dbg("Failed to read MAC address: %d", ret); 1082*b4cdae20SChristian Riesch return ret; 1083*b4cdae20SChristian Riesch } 1084*b4cdae20SChristian Riesch memcpy(dev->net->dev_addr, buf, ETH_ALEN); 1085*b4cdae20SChristian Riesch 1086*b4cdae20SChristian Riesch /* Initialize MII structure */ 1087*b4cdae20SChristian Riesch dev->mii.dev = dev->net; 1088*b4cdae20SChristian Riesch dev->mii.mdio_read = asix_mdio_read; 1089*b4cdae20SChristian Riesch dev->mii.mdio_write = asix_mdio_write; 1090*b4cdae20SChristian Riesch dev->mii.phy_id_mask = 0x1f; 1091*b4cdae20SChristian Riesch dev->mii.reg_num_mask = 0x1f; 1092*b4cdae20SChristian Riesch dev->mii.phy_id = asix_get_phy_addr(dev); 1093*b4cdae20SChristian Riesch 1094*b4cdae20SChristian Riesch dev->net->netdev_ops = &ax88772_netdev_ops; 1095*b4cdae20SChristian Riesch dev->net->ethtool_ops = &ax88772_ethtool_ops; 1096*b4cdae20SChristian Riesch dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ 1097*b4cdae20SChristian Riesch dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ 1098*b4cdae20SChristian Riesch 1099*b4cdae20SChristian Riesch embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); 1100*b4cdae20SChristian Riesch 1101*b4cdae20SChristian Riesch /* Reset the PHY to normal operation mode */ 1102*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); 1103*b4cdae20SChristian Riesch if (ret < 0) { 1104*b4cdae20SChristian Riesch dbg("Select PHY #1 failed: %d", ret); 1105*b4cdae20SChristian Riesch return ret; 1106*b4cdae20SChristian Riesch } 1107*b4cdae20SChristian Riesch 1108*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); 1109*b4cdae20SChristian Riesch if (ret < 0) 1110*b4cdae20SChristian Riesch return ret; 1111*b4cdae20SChristian Riesch 1112*b4cdae20SChristian Riesch msleep(150); 1113*b4cdae20SChristian Riesch 1114*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); 1115*b4cdae20SChristian Riesch if (ret < 0) 1116*b4cdae20SChristian Riesch return ret; 1117*b4cdae20SChristian Riesch 1118*b4cdae20SChristian Riesch msleep(150); 1119*b4cdae20SChristian Riesch 1120*b4cdae20SChristian Riesch ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); 1121*b4cdae20SChristian Riesch 1122*b4cdae20SChristian Riesch /* Read PHYID register *AFTER* the PHY was reset properly */ 1123*b4cdae20SChristian Riesch phyid = asix_get_phyid(dev); 1124*b4cdae20SChristian Riesch dbg("PHYID=0x%08x", phyid); 1125*b4cdae20SChristian Riesch 1126*b4cdae20SChristian Riesch /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 1127*b4cdae20SChristian Riesch if (dev->driver_info->flags & FLAG_FRAMING_AX) { 1128*b4cdae20SChristian Riesch /* hard_mtu is still the default - the device does not support 1129*b4cdae20SChristian Riesch jumbo eth frames */ 1130*b4cdae20SChristian Riesch dev->rx_urb_size = 2048; 1131*b4cdae20SChristian Riesch } 1132*b4cdae20SChristian Riesch 1133*b4cdae20SChristian Riesch return 0; 1134*b4cdae20SChristian Riesch } 1135*b4cdae20SChristian Riesch 1136*b4cdae20SChristian Riesch static const struct ethtool_ops ax88178_ethtool_ops = { 1137*b4cdae20SChristian Riesch .get_drvinfo = asix_get_drvinfo, 1138*b4cdae20SChristian Riesch .get_link = asix_get_link, 1139*b4cdae20SChristian Riesch .get_msglevel = usbnet_get_msglevel, 1140*b4cdae20SChristian Riesch .set_msglevel = usbnet_set_msglevel, 1141*b4cdae20SChristian Riesch .get_wol = asix_get_wol, 1142*b4cdae20SChristian Riesch .set_wol = asix_set_wol, 1143*b4cdae20SChristian Riesch .get_eeprom_len = asix_get_eeprom_len, 1144*b4cdae20SChristian Riesch .get_eeprom = asix_get_eeprom, 1145*b4cdae20SChristian Riesch .get_settings = usbnet_get_settings, 1146*b4cdae20SChristian Riesch .set_settings = usbnet_set_settings, 1147*b4cdae20SChristian Riesch .nway_reset = usbnet_nway_reset, 1148*b4cdae20SChristian Riesch }; 1149*b4cdae20SChristian Riesch 1150*b4cdae20SChristian Riesch static int marvell_phy_init(struct usbnet *dev) 1151*b4cdae20SChristian Riesch { 1152*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1153*b4cdae20SChristian Riesch u16 reg; 1154*b4cdae20SChristian Riesch 1155*b4cdae20SChristian Riesch netdev_dbg(dev->net, "marvell_phy_init()\n"); 1156*b4cdae20SChristian Riesch 1157*b4cdae20SChristian Riesch reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); 1158*b4cdae20SChristian Riesch netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); 1159*b4cdae20SChristian Riesch 1160*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, 1161*b4cdae20SChristian Riesch MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); 1162*b4cdae20SChristian Riesch 1163*b4cdae20SChristian Riesch if (data->ledmode) { 1164*b4cdae20SChristian Riesch reg = asix_mdio_read(dev->net, dev->mii.phy_id, 1165*b4cdae20SChristian Riesch MII_MARVELL_LED_CTRL); 1166*b4cdae20SChristian Riesch netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); 1167*b4cdae20SChristian Riesch 1168*b4cdae20SChristian Riesch reg &= 0xf8ff; 1169*b4cdae20SChristian Riesch reg |= (1 + 0x0100); 1170*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, 1171*b4cdae20SChristian Riesch MII_MARVELL_LED_CTRL, reg); 1172*b4cdae20SChristian Riesch 1173*b4cdae20SChristian Riesch reg = asix_mdio_read(dev->net, dev->mii.phy_id, 1174*b4cdae20SChristian Riesch MII_MARVELL_LED_CTRL); 1175*b4cdae20SChristian Riesch netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); 1176*b4cdae20SChristian Riesch reg &= 0xfc0f; 1177*b4cdae20SChristian Riesch } 1178*b4cdae20SChristian Riesch 1179*b4cdae20SChristian Riesch return 0; 1180*b4cdae20SChristian Riesch } 1181*b4cdae20SChristian Riesch 1182*b4cdae20SChristian Riesch static int rtl8211cl_phy_init(struct usbnet *dev) 1183*b4cdae20SChristian Riesch { 1184*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1185*b4cdae20SChristian Riesch 1186*b4cdae20SChristian Riesch netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); 1187*b4cdae20SChristian Riesch 1188*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); 1189*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); 1190*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, 1191*b4cdae20SChristian Riesch asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); 1192*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 1193*b4cdae20SChristian Riesch 1194*b4cdae20SChristian Riesch if (data->ledmode == 12) { 1195*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); 1196*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); 1197*b4cdae20SChristian Riesch asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 1198*b4cdae20SChristian Riesch } 1199*b4cdae20SChristian Riesch 1200*b4cdae20SChristian Riesch return 0; 1201*b4cdae20SChristian Riesch } 1202*b4cdae20SChristian Riesch 1203*b4cdae20SChristian Riesch static int marvell_led_status(struct usbnet *dev, u16 speed) 1204*b4cdae20SChristian Riesch { 1205*b4cdae20SChristian Riesch u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); 1206*b4cdae20SChristian Riesch 1207*b4cdae20SChristian Riesch netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); 1208*b4cdae20SChristian Riesch 1209*b4cdae20SChristian Riesch /* Clear out the center LED bits - 0x03F0 */ 1210*b4cdae20SChristian Riesch reg &= 0xfc0f; 1211*b4cdae20SChristian Riesch 1212*b4cdae20SChristian Riesch switch (speed) { 1213*b4cdae20SChristian Riesch case SPEED_1000: 1214*b4cdae20SChristian Riesch reg |= 0x03e0; 1215*b4cdae20SChristian Riesch break; 1216*b4cdae20SChristian Riesch case SPEED_100: 1217*b4cdae20SChristian Riesch reg |= 0x03b0; 1218*b4cdae20SChristian Riesch break; 1219*b4cdae20SChristian Riesch default: 1220*b4cdae20SChristian Riesch reg |= 0x02f0; 1221*b4cdae20SChristian Riesch } 1222*b4cdae20SChristian Riesch 1223*b4cdae20SChristian Riesch netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); 1224*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); 1225*b4cdae20SChristian Riesch 1226*b4cdae20SChristian Riesch return 0; 1227*b4cdae20SChristian Riesch } 1228*b4cdae20SChristian Riesch 1229*b4cdae20SChristian Riesch static int ax88178_reset(struct usbnet *dev) 1230*b4cdae20SChristian Riesch { 1231*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1232*b4cdae20SChristian Riesch int ret; 1233*b4cdae20SChristian Riesch __le16 eeprom; 1234*b4cdae20SChristian Riesch u8 status; 1235*b4cdae20SChristian Riesch int gpio0 = 0; 1236*b4cdae20SChristian Riesch u32 phyid; 1237*b4cdae20SChristian Riesch 1238*b4cdae20SChristian Riesch asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); 1239*b4cdae20SChristian Riesch dbg("GPIO Status: 0x%04x", status); 1240*b4cdae20SChristian Riesch 1241*b4cdae20SChristian Riesch asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); 1242*b4cdae20SChristian Riesch asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); 1243*b4cdae20SChristian Riesch asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); 1244*b4cdae20SChristian Riesch 1245*b4cdae20SChristian Riesch dbg("EEPROM index 0x17 is 0x%04x", eeprom); 1246*b4cdae20SChristian Riesch 1247*b4cdae20SChristian Riesch if (eeprom == cpu_to_le16(0xffff)) { 1248*b4cdae20SChristian Riesch data->phymode = PHY_MODE_MARVELL; 1249*b4cdae20SChristian Riesch data->ledmode = 0; 1250*b4cdae20SChristian Riesch gpio0 = 1; 1251*b4cdae20SChristian Riesch } else { 1252*b4cdae20SChristian Riesch data->phymode = le16_to_cpu(eeprom) & 0x7F; 1253*b4cdae20SChristian Riesch data->ledmode = le16_to_cpu(eeprom) >> 8; 1254*b4cdae20SChristian Riesch gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; 1255*b4cdae20SChristian Riesch } 1256*b4cdae20SChristian Riesch dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); 1257*b4cdae20SChristian Riesch 1258*b4cdae20SChristian Riesch /* Power up external GigaPHY through AX88178 GPIO pin */ 1259*b4cdae20SChristian Riesch asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); 1260*b4cdae20SChristian Riesch if ((le16_to_cpu(eeprom) >> 8) != 1) { 1261*b4cdae20SChristian Riesch asix_write_gpio(dev, 0x003c, 30); 1262*b4cdae20SChristian Riesch asix_write_gpio(dev, 0x001c, 300); 1263*b4cdae20SChristian Riesch asix_write_gpio(dev, 0x003c, 30); 1264*b4cdae20SChristian Riesch } else { 1265*b4cdae20SChristian Riesch dbg("gpio phymode == 1 path"); 1266*b4cdae20SChristian Riesch asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); 1267*b4cdae20SChristian Riesch asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); 1268*b4cdae20SChristian Riesch } 1269*b4cdae20SChristian Riesch 1270*b4cdae20SChristian Riesch /* Read PHYID register *AFTER* powering up PHY */ 1271*b4cdae20SChristian Riesch phyid = asix_get_phyid(dev); 1272*b4cdae20SChristian Riesch dbg("PHYID=0x%08x", phyid); 1273*b4cdae20SChristian Riesch 1274*b4cdae20SChristian Riesch /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ 1275*b4cdae20SChristian Riesch asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); 1276*b4cdae20SChristian Riesch 1277*b4cdae20SChristian Riesch asix_sw_reset(dev, 0); 1278*b4cdae20SChristian Riesch msleep(150); 1279*b4cdae20SChristian Riesch 1280*b4cdae20SChristian Riesch asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); 1281*b4cdae20SChristian Riesch msleep(150); 1282*b4cdae20SChristian Riesch 1283*b4cdae20SChristian Riesch asix_write_rx_ctl(dev, 0); 1284*b4cdae20SChristian Riesch 1285*b4cdae20SChristian Riesch if (data->phymode == PHY_MODE_MARVELL) { 1286*b4cdae20SChristian Riesch marvell_phy_init(dev); 1287*b4cdae20SChristian Riesch msleep(60); 1288*b4cdae20SChristian Riesch } else if (data->phymode == PHY_MODE_RTL8211CL) 1289*b4cdae20SChristian Riesch rtl8211cl_phy_init(dev); 1290*b4cdae20SChristian Riesch 1291*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, 1292*b4cdae20SChristian Riesch BMCR_RESET | BMCR_ANENABLE); 1293*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 1294*b4cdae20SChristian Riesch ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 1295*b4cdae20SChristian Riesch asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, 1296*b4cdae20SChristian Riesch ADVERTISE_1000FULL); 1297*b4cdae20SChristian Riesch 1298*b4cdae20SChristian Riesch mii_nway_restart(&dev->mii); 1299*b4cdae20SChristian Riesch 1300*b4cdae20SChristian Riesch ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); 1301*b4cdae20SChristian Riesch if (ret < 0) 1302*b4cdae20SChristian Riesch return ret; 1303*b4cdae20SChristian Riesch 1304*b4cdae20SChristian Riesch /* Rewrite MAC address */ 1305*b4cdae20SChristian Riesch memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 1306*b4cdae20SChristian Riesch ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 1307*b4cdae20SChristian Riesch data->mac_addr); 1308*b4cdae20SChristian Riesch if (ret < 0) 1309*b4cdae20SChristian Riesch return ret; 1310*b4cdae20SChristian Riesch 1311*b4cdae20SChristian Riesch ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); 1312*b4cdae20SChristian Riesch if (ret < 0) 1313*b4cdae20SChristian Riesch return ret; 1314*b4cdae20SChristian Riesch 1315*b4cdae20SChristian Riesch return 0; 1316*b4cdae20SChristian Riesch } 1317*b4cdae20SChristian Riesch 1318*b4cdae20SChristian Riesch static int ax88178_link_reset(struct usbnet *dev) 1319*b4cdae20SChristian Riesch { 1320*b4cdae20SChristian Riesch u16 mode; 1321*b4cdae20SChristian Riesch struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 1322*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1323*b4cdae20SChristian Riesch u32 speed; 1324*b4cdae20SChristian Riesch 1325*b4cdae20SChristian Riesch netdev_dbg(dev->net, "ax88178_link_reset()\n"); 1326*b4cdae20SChristian Riesch 1327*b4cdae20SChristian Riesch mii_check_media(&dev->mii, 1, 1); 1328*b4cdae20SChristian Riesch mii_ethtool_gset(&dev->mii, &ecmd); 1329*b4cdae20SChristian Riesch mode = AX88178_MEDIUM_DEFAULT; 1330*b4cdae20SChristian Riesch speed = ethtool_cmd_speed(&ecmd); 1331*b4cdae20SChristian Riesch 1332*b4cdae20SChristian Riesch if (speed == SPEED_1000) 1333*b4cdae20SChristian Riesch mode |= AX_MEDIUM_GM; 1334*b4cdae20SChristian Riesch else if (speed == SPEED_100) 1335*b4cdae20SChristian Riesch mode |= AX_MEDIUM_PS; 1336*b4cdae20SChristian Riesch else 1337*b4cdae20SChristian Riesch mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); 1338*b4cdae20SChristian Riesch 1339*b4cdae20SChristian Riesch mode |= AX_MEDIUM_ENCK; 1340*b4cdae20SChristian Riesch 1341*b4cdae20SChristian Riesch if (ecmd.duplex == DUPLEX_FULL) 1342*b4cdae20SChristian Riesch mode |= AX_MEDIUM_FD; 1343*b4cdae20SChristian Riesch else 1344*b4cdae20SChristian Riesch mode &= ~AX_MEDIUM_FD; 1345*b4cdae20SChristian Riesch 1346*b4cdae20SChristian Riesch netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 1347*b4cdae20SChristian Riesch speed, ecmd.duplex, mode); 1348*b4cdae20SChristian Riesch 1349*b4cdae20SChristian Riesch asix_write_medium_mode(dev, mode); 1350*b4cdae20SChristian Riesch 1351*b4cdae20SChristian Riesch if (data->phymode == PHY_MODE_MARVELL && data->ledmode) 1352*b4cdae20SChristian Riesch marvell_led_status(dev, speed); 1353*b4cdae20SChristian Riesch 1354*b4cdae20SChristian Riesch return 0; 1355*b4cdae20SChristian Riesch } 1356*b4cdae20SChristian Riesch 1357*b4cdae20SChristian Riesch static void ax88178_set_mfb(struct usbnet *dev) 1358*b4cdae20SChristian Riesch { 1359*b4cdae20SChristian Riesch u16 mfb = AX_RX_CTL_MFB_16384; 1360*b4cdae20SChristian Riesch u16 rxctl; 1361*b4cdae20SChristian Riesch u16 medium; 1362*b4cdae20SChristian Riesch int old_rx_urb_size = dev->rx_urb_size; 1363*b4cdae20SChristian Riesch 1364*b4cdae20SChristian Riesch if (dev->hard_mtu < 2048) { 1365*b4cdae20SChristian Riesch dev->rx_urb_size = 2048; 1366*b4cdae20SChristian Riesch mfb = AX_RX_CTL_MFB_2048; 1367*b4cdae20SChristian Riesch } else if (dev->hard_mtu < 4096) { 1368*b4cdae20SChristian Riesch dev->rx_urb_size = 4096; 1369*b4cdae20SChristian Riesch mfb = AX_RX_CTL_MFB_4096; 1370*b4cdae20SChristian Riesch } else if (dev->hard_mtu < 8192) { 1371*b4cdae20SChristian Riesch dev->rx_urb_size = 8192; 1372*b4cdae20SChristian Riesch mfb = AX_RX_CTL_MFB_8192; 1373*b4cdae20SChristian Riesch } else if (dev->hard_mtu < 16384) { 1374*b4cdae20SChristian Riesch dev->rx_urb_size = 16384; 1375*b4cdae20SChristian Riesch mfb = AX_RX_CTL_MFB_16384; 1376*b4cdae20SChristian Riesch } 1377*b4cdae20SChristian Riesch 1378*b4cdae20SChristian Riesch rxctl = asix_read_rx_ctl(dev); 1379*b4cdae20SChristian Riesch asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); 1380*b4cdae20SChristian Riesch 1381*b4cdae20SChristian Riesch medium = asix_read_medium_status(dev); 1382*b4cdae20SChristian Riesch if (dev->net->mtu > 1500) 1383*b4cdae20SChristian Riesch medium |= AX_MEDIUM_JFE; 1384*b4cdae20SChristian Riesch else 1385*b4cdae20SChristian Riesch medium &= ~AX_MEDIUM_JFE; 1386*b4cdae20SChristian Riesch asix_write_medium_mode(dev, medium); 1387*b4cdae20SChristian Riesch 1388*b4cdae20SChristian Riesch if (dev->rx_urb_size > old_rx_urb_size) 1389*b4cdae20SChristian Riesch usbnet_unlink_rx_urbs(dev); 1390*b4cdae20SChristian Riesch } 1391*b4cdae20SChristian Riesch 1392*b4cdae20SChristian Riesch static int ax88178_change_mtu(struct net_device *net, int new_mtu) 1393*b4cdae20SChristian Riesch { 1394*b4cdae20SChristian Riesch struct usbnet *dev = netdev_priv(net); 1395*b4cdae20SChristian Riesch int ll_mtu = new_mtu + net->hard_header_len + 4; 1396*b4cdae20SChristian Riesch 1397*b4cdae20SChristian Riesch netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); 1398*b4cdae20SChristian Riesch 1399*b4cdae20SChristian Riesch if (new_mtu <= 0 || ll_mtu > 16384) 1400*b4cdae20SChristian Riesch return -EINVAL; 1401*b4cdae20SChristian Riesch 1402*b4cdae20SChristian Riesch if ((ll_mtu % dev->maxpacket) == 0) 1403*b4cdae20SChristian Riesch return -EDOM; 1404*b4cdae20SChristian Riesch 1405*b4cdae20SChristian Riesch net->mtu = new_mtu; 1406*b4cdae20SChristian Riesch dev->hard_mtu = net->mtu + net->hard_header_len; 1407*b4cdae20SChristian Riesch ax88178_set_mfb(dev); 1408*b4cdae20SChristian Riesch 1409*b4cdae20SChristian Riesch return 0; 1410*b4cdae20SChristian Riesch } 1411*b4cdae20SChristian Riesch 1412*b4cdae20SChristian Riesch static const struct net_device_ops ax88178_netdev_ops = { 1413*b4cdae20SChristian Riesch .ndo_open = usbnet_open, 1414*b4cdae20SChristian Riesch .ndo_stop = usbnet_stop, 1415*b4cdae20SChristian Riesch .ndo_start_xmit = usbnet_start_xmit, 1416*b4cdae20SChristian Riesch .ndo_tx_timeout = usbnet_tx_timeout, 1417*b4cdae20SChristian Riesch .ndo_set_mac_address = asix_set_mac_address, 1418*b4cdae20SChristian Riesch .ndo_validate_addr = eth_validate_addr, 1419*b4cdae20SChristian Riesch .ndo_set_rx_mode = asix_set_multicast, 1420*b4cdae20SChristian Riesch .ndo_do_ioctl = asix_ioctl, 1421*b4cdae20SChristian Riesch .ndo_change_mtu = ax88178_change_mtu, 1422*b4cdae20SChristian Riesch }; 1423*b4cdae20SChristian Riesch 1424*b4cdae20SChristian Riesch static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) 1425*b4cdae20SChristian Riesch { 1426*b4cdae20SChristian Riesch int ret; 1427*b4cdae20SChristian Riesch u8 buf[ETH_ALEN]; 1428*b4cdae20SChristian Riesch struct asix_data *data = (struct asix_data *)&dev->data; 1429*b4cdae20SChristian Riesch 1430*b4cdae20SChristian Riesch data->eeprom_len = AX88772_EEPROM_LEN; 1431*b4cdae20SChristian Riesch 1432*b4cdae20SChristian Riesch usbnet_get_endpoints(dev,intf); 1433*b4cdae20SChristian Riesch 1434*b4cdae20SChristian Riesch /* Get the MAC address */ 1435*b4cdae20SChristian Riesch ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 1436*b4cdae20SChristian Riesch if (ret < 0) { 1437*b4cdae20SChristian Riesch dbg("Failed to read MAC address: %d", ret); 1438*b4cdae20SChristian Riesch return ret; 1439*b4cdae20SChristian Riesch } 1440*b4cdae20SChristian Riesch memcpy(dev->net->dev_addr, buf, ETH_ALEN); 1441*b4cdae20SChristian Riesch 1442*b4cdae20SChristian Riesch /* Initialize MII structure */ 1443*b4cdae20SChristian Riesch dev->mii.dev = dev->net; 1444*b4cdae20SChristian Riesch dev->mii.mdio_read = asix_mdio_read; 1445*b4cdae20SChristian Riesch dev->mii.mdio_write = asix_mdio_write; 1446*b4cdae20SChristian Riesch dev->mii.phy_id_mask = 0x1f; 1447*b4cdae20SChristian Riesch dev->mii.reg_num_mask = 0xff; 1448*b4cdae20SChristian Riesch dev->mii.supports_gmii = 1; 1449*b4cdae20SChristian Riesch dev->mii.phy_id = asix_get_phy_addr(dev); 1450*b4cdae20SChristian Riesch 1451*b4cdae20SChristian Riesch dev->net->netdev_ops = &ax88178_netdev_ops; 1452*b4cdae20SChristian Riesch dev->net->ethtool_ops = &ax88178_ethtool_ops; 1453*b4cdae20SChristian Riesch 1454*b4cdae20SChristian Riesch /* Blink LEDS so users know driver saw dongle */ 1455*b4cdae20SChristian Riesch asix_sw_reset(dev, 0); 1456*b4cdae20SChristian Riesch msleep(150); 1457*b4cdae20SChristian Riesch 1458*b4cdae20SChristian Riesch asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); 1459*b4cdae20SChristian Riesch msleep(150); 1460*b4cdae20SChristian Riesch 1461*b4cdae20SChristian Riesch /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 1462*b4cdae20SChristian Riesch if (dev->driver_info->flags & FLAG_FRAMING_AX) { 1463*b4cdae20SChristian Riesch /* hard_mtu is still the default - the device does not support 1464*b4cdae20SChristian Riesch jumbo eth frames */ 1465*b4cdae20SChristian Riesch dev->rx_urb_size = 2048; 1466*b4cdae20SChristian Riesch } 1467*b4cdae20SChristian Riesch 1468*b4cdae20SChristian Riesch return 0; 1469*b4cdae20SChristian Riesch } 1470*b4cdae20SChristian Riesch 1471*b4cdae20SChristian Riesch static const struct driver_info ax8817x_info = { 1472*b4cdae20SChristian Riesch .description = "ASIX AX8817x USB 2.0 Ethernet", 1473*b4cdae20SChristian Riesch .bind = ax88172_bind, 1474*b4cdae20SChristian Riesch .status = asix_status, 1475*b4cdae20SChristian Riesch .link_reset = ax88172_link_reset, 1476*b4cdae20SChristian Riesch .reset = ax88172_link_reset, 1477*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_LINK_INTR, 1478*b4cdae20SChristian Riesch .data = 0x00130103, 1479*b4cdae20SChristian Riesch }; 1480*b4cdae20SChristian Riesch 1481*b4cdae20SChristian Riesch static const struct driver_info dlink_dub_e100_info = { 1482*b4cdae20SChristian Riesch .description = "DLink DUB-E100 USB Ethernet", 1483*b4cdae20SChristian Riesch .bind = ax88172_bind, 1484*b4cdae20SChristian Riesch .status = asix_status, 1485*b4cdae20SChristian Riesch .link_reset = ax88172_link_reset, 1486*b4cdae20SChristian Riesch .reset = ax88172_link_reset, 1487*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_LINK_INTR, 1488*b4cdae20SChristian Riesch .data = 0x009f9d9f, 1489*b4cdae20SChristian Riesch }; 1490*b4cdae20SChristian Riesch 1491*b4cdae20SChristian Riesch static const struct driver_info netgear_fa120_info = { 1492*b4cdae20SChristian Riesch .description = "Netgear FA-120 USB Ethernet", 1493*b4cdae20SChristian Riesch .bind = ax88172_bind, 1494*b4cdae20SChristian Riesch .status = asix_status, 1495*b4cdae20SChristian Riesch .link_reset = ax88172_link_reset, 1496*b4cdae20SChristian Riesch .reset = ax88172_link_reset, 1497*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_LINK_INTR, 1498*b4cdae20SChristian Riesch .data = 0x00130103, 1499*b4cdae20SChristian Riesch }; 1500*b4cdae20SChristian Riesch 1501*b4cdae20SChristian Riesch static const struct driver_info hawking_uf200_info = { 1502*b4cdae20SChristian Riesch .description = "Hawking UF200 USB Ethernet", 1503*b4cdae20SChristian Riesch .bind = ax88172_bind, 1504*b4cdae20SChristian Riesch .status = asix_status, 1505*b4cdae20SChristian Riesch .link_reset = ax88172_link_reset, 1506*b4cdae20SChristian Riesch .reset = ax88172_link_reset, 1507*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_LINK_INTR, 1508*b4cdae20SChristian Riesch .data = 0x001f1d1f, 1509*b4cdae20SChristian Riesch }; 1510*b4cdae20SChristian Riesch 1511*b4cdae20SChristian Riesch static const struct driver_info ax88772_info = { 1512*b4cdae20SChristian Riesch .description = "ASIX AX88772 USB 2.0 Ethernet", 1513*b4cdae20SChristian Riesch .bind = ax88772_bind, 1514*b4cdae20SChristian Riesch .status = asix_status, 1515*b4cdae20SChristian Riesch .link_reset = ax88772_link_reset, 1516*b4cdae20SChristian Riesch .reset = ax88772_reset, 1517*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, 1518*b4cdae20SChristian Riesch .rx_fixup = asix_rx_fixup, 1519*b4cdae20SChristian Riesch .tx_fixup = asix_tx_fixup, 1520*b4cdae20SChristian Riesch }; 1521*b4cdae20SChristian Riesch 1522*b4cdae20SChristian Riesch static const struct driver_info ax88178_info = { 1523*b4cdae20SChristian Riesch .description = "ASIX AX88178 USB 2.0 Ethernet", 1524*b4cdae20SChristian Riesch .bind = ax88178_bind, 1525*b4cdae20SChristian Riesch .status = asix_status, 1526*b4cdae20SChristian Riesch .link_reset = ax88178_link_reset, 1527*b4cdae20SChristian Riesch .reset = ax88178_reset, 1528*b4cdae20SChristian Riesch .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, 1529*b4cdae20SChristian Riesch .rx_fixup = asix_rx_fixup, 1530*b4cdae20SChristian Riesch .tx_fixup = asix_tx_fixup, 1531*b4cdae20SChristian Riesch }; 1532*b4cdae20SChristian Riesch 1533*b4cdae20SChristian Riesch static const struct usb_device_id products [] = { 1534*b4cdae20SChristian Riesch { 1535*b4cdae20SChristian Riesch // Linksys USB200M 1536*b4cdae20SChristian Riesch USB_DEVICE (0x077b, 0x2226), 1537*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1538*b4cdae20SChristian Riesch }, { 1539*b4cdae20SChristian Riesch // Netgear FA120 1540*b4cdae20SChristian Riesch USB_DEVICE (0x0846, 0x1040), 1541*b4cdae20SChristian Riesch .driver_info = (unsigned long) &netgear_fa120_info, 1542*b4cdae20SChristian Riesch }, { 1543*b4cdae20SChristian Riesch // DLink DUB-E100 1544*b4cdae20SChristian Riesch USB_DEVICE (0x2001, 0x1a00), 1545*b4cdae20SChristian Riesch .driver_info = (unsigned long) &dlink_dub_e100_info, 1546*b4cdae20SChristian Riesch }, { 1547*b4cdae20SChristian Riesch // Intellinet, ST Lab USB Ethernet 1548*b4cdae20SChristian Riesch USB_DEVICE (0x0b95, 0x1720), 1549*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1550*b4cdae20SChristian Riesch }, { 1551*b4cdae20SChristian Riesch // Hawking UF200, TrendNet TU2-ET100 1552*b4cdae20SChristian Riesch USB_DEVICE (0x07b8, 0x420a), 1553*b4cdae20SChristian Riesch .driver_info = (unsigned long) &hawking_uf200_info, 1554*b4cdae20SChristian Riesch }, { 1555*b4cdae20SChristian Riesch // Billionton Systems, USB2AR 1556*b4cdae20SChristian Riesch USB_DEVICE (0x08dd, 0x90ff), 1557*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1558*b4cdae20SChristian Riesch }, { 1559*b4cdae20SChristian Riesch // ATEN UC210T 1560*b4cdae20SChristian Riesch USB_DEVICE (0x0557, 0x2009), 1561*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1562*b4cdae20SChristian Riesch }, { 1563*b4cdae20SChristian Riesch // Buffalo LUA-U2-KTX 1564*b4cdae20SChristian Riesch USB_DEVICE (0x0411, 0x003d), 1565*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1566*b4cdae20SChristian Riesch }, { 1567*b4cdae20SChristian Riesch // Buffalo LUA-U2-GT 10/100/1000 1568*b4cdae20SChristian Riesch USB_DEVICE (0x0411, 0x006e), 1569*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1570*b4cdae20SChristian Riesch }, { 1571*b4cdae20SChristian Riesch // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" 1572*b4cdae20SChristian Riesch USB_DEVICE (0x6189, 0x182d), 1573*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1574*b4cdae20SChristian Riesch }, { 1575*b4cdae20SChristian Riesch // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" 1576*b4cdae20SChristian Riesch USB_DEVICE (0x0df6, 0x0056), 1577*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1578*b4cdae20SChristian Riesch }, { 1579*b4cdae20SChristian Riesch // corega FEther USB2-TX 1580*b4cdae20SChristian Riesch USB_DEVICE (0x07aa, 0x0017), 1581*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1582*b4cdae20SChristian Riesch }, { 1583*b4cdae20SChristian Riesch // Surecom EP-1427X-2 1584*b4cdae20SChristian Riesch USB_DEVICE (0x1189, 0x0893), 1585*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1586*b4cdae20SChristian Riesch }, { 1587*b4cdae20SChristian Riesch // goodway corp usb gwusb2e 1588*b4cdae20SChristian Riesch USB_DEVICE (0x1631, 0x6200), 1589*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1590*b4cdae20SChristian Riesch }, { 1591*b4cdae20SChristian Riesch // JVC MP-PRX1 Port Replicator 1592*b4cdae20SChristian Riesch USB_DEVICE (0x04f1, 0x3008), 1593*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax8817x_info, 1594*b4cdae20SChristian Riesch }, { 1595*b4cdae20SChristian Riesch // ASIX AX88772B 10/100 1596*b4cdae20SChristian Riesch USB_DEVICE (0x0b95, 0x772b), 1597*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1598*b4cdae20SChristian Riesch }, { 1599*b4cdae20SChristian Riesch // ASIX AX88772 10/100 1600*b4cdae20SChristian Riesch USB_DEVICE (0x0b95, 0x7720), 1601*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1602*b4cdae20SChristian Riesch }, { 1603*b4cdae20SChristian Riesch // ASIX AX88178 10/100/1000 1604*b4cdae20SChristian Riesch USB_DEVICE (0x0b95, 0x1780), 1605*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1606*b4cdae20SChristian Riesch }, { 1607*b4cdae20SChristian Riesch // Logitec LAN-GTJ/U2A 1608*b4cdae20SChristian Riesch USB_DEVICE (0x0789, 0x0160), 1609*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1610*b4cdae20SChristian Riesch }, { 1611*b4cdae20SChristian Riesch // Linksys USB200M Rev 2 1612*b4cdae20SChristian Riesch USB_DEVICE (0x13b1, 0x0018), 1613*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1614*b4cdae20SChristian Riesch }, { 1615*b4cdae20SChristian Riesch // 0Q0 cable ethernet 1616*b4cdae20SChristian Riesch USB_DEVICE (0x1557, 0x7720), 1617*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1618*b4cdae20SChristian Riesch }, { 1619*b4cdae20SChristian Riesch // DLink DUB-E100 H/W Ver B1 1620*b4cdae20SChristian Riesch USB_DEVICE (0x07d1, 0x3c05), 1621*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1622*b4cdae20SChristian Riesch }, { 1623*b4cdae20SChristian Riesch // DLink DUB-E100 H/W Ver B1 Alternate 1624*b4cdae20SChristian Riesch USB_DEVICE (0x2001, 0x3c05), 1625*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1626*b4cdae20SChristian Riesch }, { 1627*b4cdae20SChristian Riesch // Linksys USB1000 1628*b4cdae20SChristian Riesch USB_DEVICE (0x1737, 0x0039), 1629*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1630*b4cdae20SChristian Riesch }, { 1631*b4cdae20SChristian Riesch // IO-DATA ETG-US2 1632*b4cdae20SChristian Riesch USB_DEVICE (0x04bb, 0x0930), 1633*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1634*b4cdae20SChristian Riesch }, { 1635*b4cdae20SChristian Riesch // Belkin F5D5055 1636*b4cdae20SChristian Riesch USB_DEVICE(0x050d, 0x5055), 1637*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1638*b4cdae20SChristian Riesch }, { 1639*b4cdae20SChristian Riesch // Apple USB Ethernet Adapter 1640*b4cdae20SChristian Riesch USB_DEVICE(0x05ac, 0x1402), 1641*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1642*b4cdae20SChristian Riesch }, { 1643*b4cdae20SChristian Riesch // Cables-to-Go USB Ethernet Adapter 1644*b4cdae20SChristian Riesch USB_DEVICE(0x0b95, 0x772a), 1645*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1646*b4cdae20SChristian Riesch }, { 1647*b4cdae20SChristian Riesch // ABOCOM for pci 1648*b4cdae20SChristian Riesch USB_DEVICE(0x14ea, 0xab11), 1649*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88178_info, 1650*b4cdae20SChristian Riesch }, { 1651*b4cdae20SChristian Riesch // ASIX 88772a 1652*b4cdae20SChristian Riesch USB_DEVICE(0x0db0, 0xa877), 1653*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1654*b4cdae20SChristian Riesch }, { 1655*b4cdae20SChristian Riesch // Asus USB Ethernet Adapter 1656*b4cdae20SChristian Riesch USB_DEVICE (0x0b95, 0x7e2b), 1657*b4cdae20SChristian Riesch .driver_info = (unsigned long) &ax88772_info, 1658*b4cdae20SChristian Riesch }, 1659*b4cdae20SChristian Riesch { }, // END 1660*b4cdae20SChristian Riesch }; 1661*b4cdae20SChristian Riesch MODULE_DEVICE_TABLE(usb, products); 1662*b4cdae20SChristian Riesch 1663*b4cdae20SChristian Riesch static struct usb_driver asix_driver = { 1664*b4cdae20SChristian Riesch .name = DRIVER_NAME, 1665*b4cdae20SChristian Riesch .id_table = products, 1666*b4cdae20SChristian Riesch .probe = usbnet_probe, 1667*b4cdae20SChristian Riesch .suspend = usbnet_suspend, 1668*b4cdae20SChristian Riesch .resume = usbnet_resume, 1669*b4cdae20SChristian Riesch .disconnect = usbnet_disconnect, 1670*b4cdae20SChristian Riesch .supports_autosuspend = 1, 1671*b4cdae20SChristian Riesch .disable_hub_initiated_lpm = 1, 1672*b4cdae20SChristian Riesch }; 1673*b4cdae20SChristian Riesch 1674*b4cdae20SChristian Riesch module_usb_driver(asix_driver); 1675*b4cdae20SChristian Riesch 1676*b4cdae20SChristian Riesch MODULE_AUTHOR("David Hollis"); 1677*b4cdae20SChristian Riesch MODULE_VERSION(DRIVER_VERSION); 1678*b4cdae20SChristian Riesch MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); 1679*b4cdae20SChristian Riesch MODULE_LICENSE("GPL"); 1680*b4cdae20SChristian Riesch 1681