xref: /openbmc/linux/drivers/net/usb/asix_common.c (revision b4cdae20ef956fb80b231cbbcfcdb446fed763ca)
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