diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-06 12:48:31 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-08-06 12:48:31 -0400 |
commit | c87985a3ce723995fc7b25e598238d67154108a1 (patch) | |
tree | e60def1b77c25c1d74180f62e8a5603f9826f209 /drivers/net/usb | |
parent | d155255a344c417acad74156654295a2964e6b81 (diff) | |
parent | 0d7614f09c1ebdbaa1599a5aba7593f147bf96ee (diff) |
Merge tty-next into 3.6-rc1
This handles the merge issue in:
arch/um/drivers/line.c
arch/um/drivers/line.h
And resolves the duplicate patches that were in both trees do to the
tty-next branch not getting merged into 3.6-rc1.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/usb/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/usb/asix.h | 218 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 631 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c (renamed from drivers/net/usb/asix.c) | 666 | ||||
-rw-r--r-- | drivers/net/usb/ax88172a.c | 414 | ||||
-rw-r--r-- | drivers/net/usb/cdc-phonet.c | 6 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 68 | ||||
-rw-r--r-- | drivers/net/usb/kaweth.c | 2 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.c | 4 | ||||
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 368 | ||||
-rw-r--r-- | drivers/net/usb/smsc75xx.c | 4 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 36 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.c | 77 |
14 files changed, 1613 insertions, 883 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 833e32f8d63b..c1ae76968f47 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig | |||
@@ -134,6 +134,7 @@ config USB_NET_AX8817X | |||
134 | tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" | 134 | tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" |
135 | depends on USB_USBNET | 135 | depends on USB_USBNET |
136 | select CRC32 | 136 | select CRC32 |
137 | select PHYLIB | ||
137 | default y | 138 | default y |
138 | help | 139 | help |
139 | This option adds support for ASIX AX88xxx based USB 2.0 | 140 | This option adds support for ASIX AX88xxx based USB 2.0 |
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index a2e2d72c52a0..bf063008c1af 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o | |||
8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o | 8 | obj-$(CONFIG_USB_RTL8150) += rtl8150.o |
9 | obj-$(CONFIG_USB_HSO) += hso.o | 9 | obj-$(CONFIG_USB_HSO) += hso.o |
10 | obj-$(CONFIG_USB_NET_AX8817X) += asix.o | 10 | obj-$(CONFIG_USB_NET_AX8817X) += asix.o |
11 | asix-y := asix_devices.o asix_common.o ax88172a.o | ||
11 | obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o | 12 | obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o |
12 | obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o | 13 | obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o |
13 | obj-$(CONFIG_USB_NET_DM9601) += dm9601.o | 14 | obj-$(CONFIG_USB_NET_DM9601) += dm9601.o |
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h new file mode 100644 index 000000000000..e889631161b8 --- /dev/null +++ b/drivers/net/usb/asix.h | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * ASIX AX8817X based USB 2.0 Ethernet Devices | ||
3 | * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | ||
4 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
5 | * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | ||
6 | * Copyright (c) 2002-2003 TiVo Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #ifndef _ASIX_H | ||
24 | #define _ASIX_H | ||
25 | |||
26 | // #define DEBUG // error path messages, extra info | ||
27 | // #define VERBOSE // more; success messages | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/kmod.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | #include <linux/mii.h> | ||
37 | #include <linux/usb.h> | ||
38 | #include <linux/crc32.h> | ||
39 | #include <linux/usb/usbnet.h> | ||
40 | #include <linux/slab.h> | ||
41 | #include <linux/if_vlan.h> | ||
42 | |||
43 | #define DRIVER_VERSION "22-Dec-2011" | ||
44 | #define DRIVER_NAME "asix" | ||
45 | |||
46 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | ||
47 | |||
48 | #define AX_CMD_SET_SW_MII 0x06 | ||
49 | #define AX_CMD_READ_MII_REG 0x07 | ||
50 | #define AX_CMD_WRITE_MII_REG 0x08 | ||
51 | #define AX_CMD_SET_HW_MII 0x0a | ||
52 | #define AX_CMD_READ_EEPROM 0x0b | ||
53 | #define AX_CMD_WRITE_EEPROM 0x0c | ||
54 | #define AX_CMD_WRITE_ENABLE 0x0d | ||
55 | #define AX_CMD_WRITE_DISABLE 0x0e | ||
56 | #define AX_CMD_READ_RX_CTL 0x0f | ||
57 | #define AX_CMD_WRITE_RX_CTL 0x10 | ||
58 | #define AX_CMD_READ_IPG012 0x11 | ||
59 | #define AX_CMD_WRITE_IPG0 0x12 | ||
60 | #define AX_CMD_WRITE_IPG1 0x13 | ||
61 | #define AX_CMD_READ_NODE_ID 0x13 | ||
62 | #define AX_CMD_WRITE_NODE_ID 0x14 | ||
63 | #define AX_CMD_WRITE_IPG2 0x14 | ||
64 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | ||
65 | #define AX88172_CMD_READ_NODE_ID 0x17 | ||
66 | #define AX_CMD_READ_PHY_ID 0x19 | ||
67 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
68 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | ||
69 | #define AX_CMD_READ_MONITOR_MODE 0x1c | ||
70 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | ||
71 | #define AX_CMD_READ_GPIOS 0x1e | ||
72 | #define AX_CMD_WRITE_GPIOS 0x1f | ||
73 | #define AX_CMD_SW_RESET 0x20 | ||
74 | #define AX_CMD_SW_PHY_STATUS 0x21 | ||
75 | #define AX_CMD_SW_PHY_SELECT 0x22 | ||
76 | |||
77 | #define AX_PHY_SELECT_MASK (BIT(3) | BIT(2)) | ||
78 | #define AX_PHY_SELECT_INTERNAL 0 | ||
79 | #define AX_PHY_SELECT_EXTERNAL BIT(2) | ||
80 | |||
81 | #define AX_MONITOR_MODE 0x01 | ||
82 | #define AX_MONITOR_LINK 0x02 | ||
83 | #define AX_MONITOR_MAGIC 0x04 | ||
84 | #define AX_MONITOR_HSFS 0x10 | ||
85 | |||
86 | /* AX88172 Medium Status Register values */ | ||
87 | #define AX88172_MEDIUM_FD 0x02 | ||
88 | #define AX88172_MEDIUM_TX 0x04 | ||
89 | #define AX88172_MEDIUM_FC 0x10 | ||
90 | #define AX88172_MEDIUM_DEFAULT \ | ||
91 | ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | ||
92 | |||
93 | #define AX_MCAST_FILTER_SIZE 8 | ||
94 | #define AX_MAX_MCAST 64 | ||
95 | |||
96 | #define AX_SWRESET_CLEAR 0x00 | ||
97 | #define AX_SWRESET_RR 0x01 | ||
98 | #define AX_SWRESET_RT 0x02 | ||
99 | #define AX_SWRESET_PRTE 0x04 | ||
100 | #define AX_SWRESET_PRL 0x08 | ||
101 | #define AX_SWRESET_BZ 0x10 | ||
102 | #define AX_SWRESET_IPRL 0x20 | ||
103 | #define AX_SWRESET_IPPD 0x40 | ||
104 | |||
105 | #define AX88772_IPG0_DEFAULT 0x15 | ||
106 | #define AX88772_IPG1_DEFAULT 0x0c | ||
107 | #define AX88772_IPG2_DEFAULT 0x12 | ||
108 | |||
109 | /* AX88772 & AX88178 Medium Mode Register */ | ||
110 | #define AX_MEDIUM_PF 0x0080 | ||
111 | #define AX_MEDIUM_JFE 0x0040 | ||
112 | #define AX_MEDIUM_TFC 0x0020 | ||
113 | #define AX_MEDIUM_RFC 0x0010 | ||
114 | #define AX_MEDIUM_ENCK 0x0008 | ||
115 | #define AX_MEDIUM_AC 0x0004 | ||
116 | #define AX_MEDIUM_FD 0x0002 | ||
117 | #define AX_MEDIUM_GM 0x0001 | ||
118 | #define AX_MEDIUM_SM 0x1000 | ||
119 | #define AX_MEDIUM_SBP 0x0800 | ||
120 | #define AX_MEDIUM_PS 0x0200 | ||
121 | #define AX_MEDIUM_RE 0x0100 | ||
122 | |||
123 | #define AX88178_MEDIUM_DEFAULT \ | ||
124 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | ||
125 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | ||
126 | AX_MEDIUM_RE) | ||
127 | |||
128 | #define AX88772_MEDIUM_DEFAULT \ | ||
129 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | ||
130 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | ||
131 | AX_MEDIUM_AC | AX_MEDIUM_RE) | ||
132 | |||
133 | /* AX88772 & AX88178 RX_CTL values */ | ||
134 | #define AX_RX_CTL_SO 0x0080 | ||
135 | #define AX_RX_CTL_AP 0x0020 | ||
136 | #define AX_RX_CTL_AM 0x0010 | ||
137 | #define AX_RX_CTL_AB 0x0008 | ||
138 | #define AX_RX_CTL_SEP 0x0004 | ||
139 | #define AX_RX_CTL_AMALL 0x0002 | ||
140 | #define AX_RX_CTL_PRO 0x0001 | ||
141 | #define AX_RX_CTL_MFB_2048 0x0000 | ||
142 | #define AX_RX_CTL_MFB_4096 0x0100 | ||
143 | #define AX_RX_CTL_MFB_8192 0x0200 | ||
144 | #define AX_RX_CTL_MFB_16384 0x0300 | ||
145 | |||
146 | #define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) | ||
147 | |||
148 | /* GPIO 0 .. 2 toggles */ | ||
149 | #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | ||
150 | #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | ||
151 | #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | ||
152 | #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | ||
153 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | ||
154 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | ||
155 | #define AX_GPIO_RESERVED 0x40 /* Reserved */ | ||
156 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | ||
157 | |||
158 | #define AX_EEPROM_MAGIC 0xdeadbeef | ||
159 | #define AX_EEPROM_LEN 0x200 | ||
160 | |||
161 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | ||
162 | struct asix_data { | ||
163 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | ||
164 | u8 mac_addr[ETH_ALEN]; | ||
165 | u8 phymode; | ||
166 | u8 ledmode; | ||
167 | u8 res; | ||
168 | }; | ||
169 | |||
170 | int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
171 | u16 size, void *data); | ||
172 | |||
173 | int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
174 | u16 size, void *data); | ||
175 | |||
176 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, | ||
177 | u16 index, u16 size, void *data); | ||
178 | |||
179 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb); | ||
180 | |||
181 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
182 | gfp_t flags); | ||
183 | |||
184 | int asix_set_sw_mii(struct usbnet *dev); | ||
185 | int asix_set_hw_mii(struct usbnet *dev); | ||
186 | |||
187 | int asix_read_phy_addr(struct usbnet *dev, int internal); | ||
188 | int asix_get_phy_addr(struct usbnet *dev); | ||
189 | |||
190 | int asix_sw_reset(struct usbnet *dev, u8 flags); | ||
191 | |||
192 | u16 asix_read_rx_ctl(struct usbnet *dev); | ||
193 | int asix_write_rx_ctl(struct usbnet *dev, u16 mode); | ||
194 | |||
195 | u16 asix_read_medium_status(struct usbnet *dev); | ||
196 | int asix_write_medium_mode(struct usbnet *dev, u16 mode); | ||
197 | |||
198 | int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); | ||
199 | |||
200 | void asix_set_multicast(struct net_device *net); | ||
201 | |||
202 | int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); | ||
203 | void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); | ||
204 | |||
205 | void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); | ||
206 | int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); | ||
207 | |||
208 | int asix_get_eeprom_len(struct net_device *net); | ||
209 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
210 | u8 *data); | ||
211 | int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
212 | u8 *data); | ||
213 | |||
214 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); | ||
215 | |||
216 | int asix_set_mac_address(struct net_device *net, void *p); | ||
217 | |||
218 | #endif /* _ASIX_H */ | ||
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c new file mode 100644 index 000000000000..774d9ce2dafc --- /dev/null +++ b/drivers/net/usb/asix_common.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * ASIX AX8817X based USB 2.0 Ethernet Devices | ||
3 | * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | ||
4 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
5 | * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | ||
6 | * Copyright (c) 2002-2003 TiVo Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include "asix.h" | ||
24 | |||
25 | int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
26 | u16 size, void *data) | ||
27 | { | ||
28 | void *buf; | ||
29 | int err = -ENOMEM; | ||
30 | |||
31 | netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
32 | cmd, value, index, size); | ||
33 | |||
34 | buf = kmalloc(size, GFP_KERNEL); | ||
35 | if (!buf) | ||
36 | goto out; | ||
37 | |||
38 | err = usb_control_msg( | ||
39 | dev->udev, | ||
40 | usb_rcvctrlpipe(dev->udev, 0), | ||
41 | cmd, | ||
42 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
43 | value, | ||
44 | index, | ||
45 | buf, | ||
46 | size, | ||
47 | USB_CTRL_GET_TIMEOUT); | ||
48 | if (err == size) | ||
49 | memcpy(data, buf, size); | ||
50 | else if (err >= 0) | ||
51 | err = -EINVAL; | ||
52 | kfree(buf); | ||
53 | |||
54 | out: | ||
55 | return err; | ||
56 | } | ||
57 | |||
58 | int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
59 | u16 size, void *data) | ||
60 | { | ||
61 | void *buf = NULL; | ||
62 | int err = -ENOMEM; | ||
63 | |||
64 | netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
65 | cmd, value, index, size); | ||
66 | |||
67 | if (data) { | ||
68 | buf = kmemdup(data, size, GFP_KERNEL); | ||
69 | if (!buf) | ||
70 | goto out; | ||
71 | } | ||
72 | |||
73 | err = usb_control_msg( | ||
74 | dev->udev, | ||
75 | usb_sndctrlpipe(dev->udev, 0), | ||
76 | cmd, | ||
77 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
78 | value, | ||
79 | index, | ||
80 | buf, | ||
81 | size, | ||
82 | USB_CTRL_SET_TIMEOUT); | ||
83 | kfree(buf); | ||
84 | |||
85 | out: | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | static void asix_async_cmd_callback(struct urb *urb) | ||
90 | { | ||
91 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
92 | int status = urb->status; | ||
93 | |||
94 | if (status < 0) | ||
95 | printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", | ||
96 | status); | ||
97 | |||
98 | kfree(req); | ||
99 | usb_free_urb(urb); | ||
100 | } | ||
101 | |||
102 | void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
103 | u16 size, void *data) | ||
104 | { | ||
105 | struct usb_ctrlrequest *req; | ||
106 | int status; | ||
107 | struct urb *urb; | ||
108 | |||
109 | netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
110 | cmd, value, index, size); | ||
111 | |||
112 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
113 | if (!urb) { | ||
114 | netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); | ||
115 | return; | ||
116 | } | ||
117 | |||
118 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
119 | if (!req) { | ||
120 | netdev_err(dev->net, "Failed to allocate memory for control request\n"); | ||
121 | usb_free_urb(urb); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
126 | req->bRequest = cmd; | ||
127 | req->wValue = cpu_to_le16(value); | ||
128 | req->wIndex = cpu_to_le16(index); | ||
129 | req->wLength = cpu_to_le16(size); | ||
130 | |||
131 | usb_fill_control_urb(urb, dev->udev, | ||
132 | usb_sndctrlpipe(dev->udev, 0), | ||
133 | (void *)req, data, size, | ||
134 | asix_async_cmd_callback, req); | ||
135 | |||
136 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
137 | if (status < 0) { | ||
138 | netdev_err(dev->net, "Error submitting the control message: status=%d\n", | ||
139 | status); | ||
140 | kfree(req); | ||
141 | usb_free_urb(urb); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
146 | { | ||
147 | int offset = 0; | ||
148 | |||
149 | while (offset + sizeof(u32) < skb->len) { | ||
150 | struct sk_buff *ax_skb; | ||
151 | u16 size; | ||
152 | u32 header = get_unaligned_le32(skb->data + offset); | ||
153 | |||
154 | offset += sizeof(u32); | ||
155 | |||
156 | /* get the packet length */ | ||
157 | size = (u16) (header & 0x7ff); | ||
158 | if (size != ((~header >> 16) & 0x07ff)) { | ||
159 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | ||
164 | (size + offset > skb->len)) { | ||
165 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | ||
166 | size); | ||
167 | return 0; | ||
168 | } | ||
169 | ax_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
170 | if (!ax_skb) | ||
171 | return 0; | ||
172 | |||
173 | skb_put(ax_skb, size); | ||
174 | memcpy(ax_skb->data, skb->data + offset, size); | ||
175 | usbnet_skb_return(dev, ax_skb); | ||
176 | |||
177 | offset += (size + 1) & 0xfffe; | ||
178 | } | ||
179 | |||
180 | if (skb->len != offset) { | ||
181 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", | ||
182 | skb->len); | ||
183 | return 0; | ||
184 | } | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
189 | gfp_t flags) | ||
190 | { | ||
191 | int padlen; | ||
192 | int headroom = skb_headroom(skb); | ||
193 | int tailroom = skb_tailroom(skb); | ||
194 | u32 packet_len; | ||
195 | u32 padbytes = 0xffff0000; | ||
196 | |||
197 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | ||
198 | |||
199 | /* We need to push 4 bytes in front of frame (packet_len) | ||
200 | * and maybe add 4 bytes after the end (if padlen is 4) | ||
201 | * | ||
202 | * Avoid skb_copy_expand() expensive call, using following rules : | ||
203 | * - We are allowed to push 4 bytes in headroom if skb_header_cloned() | ||
204 | * is false (and if we have 4 bytes of headroom) | ||
205 | * - We are allowed to put 4 bytes at tail if skb_cloned() | ||
206 | * is false (and if we have 4 bytes of tailroom) | ||
207 | * | ||
208 | * TCP packets for example are cloned, but skb_header_release() | ||
209 | * was called in tcp stack, allowing us to use headroom for our needs. | ||
210 | */ | ||
211 | if (!skb_header_cloned(skb) && | ||
212 | !(padlen && skb_cloned(skb)) && | ||
213 | headroom + tailroom >= 4 + padlen) { | ||
214 | /* following should not happen, but better be safe */ | ||
215 | if (headroom < 4 || | ||
216 | tailroom < padlen) { | ||
217 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | ||
218 | skb_set_tail_pointer(skb, skb->len); | ||
219 | } | ||
220 | } else { | ||
221 | struct sk_buff *skb2; | ||
222 | |||
223 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
224 | dev_kfree_skb_any(skb); | ||
225 | skb = skb2; | ||
226 | if (!skb) | ||
227 | return NULL; | ||
228 | } | ||
229 | |||
230 | packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; | ||
231 | skb_push(skb, 4); | ||
232 | cpu_to_le32s(&packet_len); | ||
233 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
234 | |||
235 | if (padlen) { | ||
236 | cpu_to_le32s(&padbytes); | ||
237 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
238 | skb_put(skb, sizeof(padbytes)); | ||
239 | } | ||
240 | return skb; | ||
241 | } | ||
242 | |||
243 | int asix_set_sw_mii(struct usbnet *dev) | ||
244 | { | ||
245 | int ret; | ||
246 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
247 | if (ret < 0) | ||
248 | netdev_err(dev->net, "Failed to enable software MII access\n"); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | int asix_set_hw_mii(struct usbnet *dev) | ||
253 | { | ||
254 | int ret; | ||
255 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
256 | if (ret < 0) | ||
257 | netdev_err(dev->net, "Failed to enable hardware MII access\n"); | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | int asix_read_phy_addr(struct usbnet *dev, int internal) | ||
262 | { | ||
263 | int offset = (internal ? 1 : 0); | ||
264 | u8 buf[2]; | ||
265 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | ||
266 | |||
267 | netdev_dbg(dev->net, "asix_get_phy_addr()\n"); | ||
268 | |||
269 | if (ret < 0) { | ||
270 | netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); | ||
271 | goto out; | ||
272 | } | ||
273 | netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", | ||
274 | *((__le16 *)buf)); | ||
275 | ret = buf[offset]; | ||
276 | |||
277 | out: | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | int asix_get_phy_addr(struct usbnet *dev) | ||
282 | { | ||
283 | /* return the address of the internal phy */ | ||
284 | return asix_read_phy_addr(dev, 1); | ||
285 | } | ||
286 | |||
287 | |||
288 | int asix_sw_reset(struct usbnet *dev, u8 flags) | ||
289 | { | ||
290 | int ret; | ||
291 | |||
292 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | ||
293 | if (ret < 0) | ||
294 | netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); | ||
295 | |||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | u16 asix_read_rx_ctl(struct usbnet *dev) | ||
300 | { | ||
301 | __le16 v; | ||
302 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | ||
303 | |||
304 | if (ret < 0) { | ||
305 | netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); | ||
306 | goto out; | ||
307 | } | ||
308 | ret = le16_to_cpu(v); | ||
309 | out: | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
314 | { | ||
315 | int ret; | ||
316 | |||
317 | netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); | ||
318 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
319 | if (ret < 0) | ||
320 | netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", | ||
321 | mode, ret); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | u16 asix_read_medium_status(struct usbnet *dev) | ||
327 | { | ||
328 | __le16 v; | ||
329 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | ||
330 | |||
331 | if (ret < 0) { | ||
332 | netdev_err(dev->net, "Error reading Medium Status register: %02x\n", | ||
333 | ret); | ||
334 | return ret; /* TODO: callers not checking for error ret */ | ||
335 | } | ||
336 | |||
337 | return le16_to_cpu(v); | ||
338 | |||
339 | } | ||
340 | |||
341 | int asix_write_medium_mode(struct usbnet *dev, u16 mode) | ||
342 | { | ||
343 | int ret; | ||
344 | |||
345 | netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); | ||
346 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
347 | if (ret < 0) | ||
348 | netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", | ||
349 | mode, ret); | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
355 | { | ||
356 | int ret; | ||
357 | |||
358 | netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); | ||
359 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
360 | if (ret < 0) | ||
361 | netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", | ||
362 | value, ret); | ||
363 | |||
364 | if (sleep) | ||
365 | msleep(sleep); | ||
366 | |||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * AX88772 & AX88178 have a 16-bit RX_CTL value | ||
372 | */ | ||
373 | void asix_set_multicast(struct net_device *net) | ||
374 | { | ||
375 | struct usbnet *dev = netdev_priv(net); | ||
376 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
377 | u16 rx_ctl = AX_DEFAULT_RX_CTL; | ||
378 | |||
379 | if (net->flags & IFF_PROMISC) { | ||
380 | rx_ctl |= AX_RX_CTL_PRO; | ||
381 | } else if (net->flags & IFF_ALLMULTI || | ||
382 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
383 | rx_ctl |= AX_RX_CTL_AMALL; | ||
384 | } else if (netdev_mc_empty(net)) { | ||
385 | /* just broadcast and directed */ | ||
386 | } else { | ||
387 | /* We use the 20 byte dev->data | ||
388 | * for our 8 byte filter buffer | ||
389 | * to avoid allocating memory that | ||
390 | * is tricky to free later */ | ||
391 | struct netdev_hw_addr *ha; | ||
392 | u32 crc_bits; | ||
393 | |||
394 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
395 | |||
396 | /* Build the multicast hash filter. */ | ||
397 | netdev_for_each_mc_addr(ha, net) { | ||
398 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
399 | data->multi_filter[crc_bits >> 3] |= | ||
400 | 1 << (crc_bits & 7); | ||
401 | } | ||
402 | |||
403 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
404 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
405 | |||
406 | rx_ctl |= AX_RX_CTL_AM; | ||
407 | } | ||
408 | |||
409 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
410 | } | ||
411 | |||
412 | int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
413 | { | ||
414 | struct usbnet *dev = netdev_priv(netdev); | ||
415 | __le16 res; | ||
416 | |||
417 | mutex_lock(&dev->phy_mutex); | ||
418 | asix_set_sw_mii(dev); | ||
419 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | ||
420 | (__u16)loc, 2, &res); | ||
421 | asix_set_hw_mii(dev); | ||
422 | mutex_unlock(&dev->phy_mutex); | ||
423 | |||
424 | netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | ||
425 | phy_id, loc, le16_to_cpu(res)); | ||
426 | |||
427 | return le16_to_cpu(res); | ||
428 | } | ||
429 | |||
430 | void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
431 | { | ||
432 | struct usbnet *dev = netdev_priv(netdev); | ||
433 | __le16 res = cpu_to_le16(val); | ||
434 | |||
435 | netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | ||
436 | phy_id, loc, val); | ||
437 | mutex_lock(&dev->phy_mutex); | ||
438 | asix_set_sw_mii(dev); | ||
439 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
440 | asix_set_hw_mii(dev); | ||
441 | mutex_unlock(&dev->phy_mutex); | ||
442 | } | ||
443 | |||
444 | void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
445 | { | ||
446 | struct usbnet *dev = netdev_priv(net); | ||
447 | u8 opt; | ||
448 | |||
449 | if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
450 | wolinfo->supported = 0; | ||
451 | wolinfo->wolopts = 0; | ||
452 | return; | ||
453 | } | ||
454 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
455 | wolinfo->wolopts = 0; | ||
456 | if (opt & AX_MONITOR_LINK) | ||
457 | wolinfo->wolopts |= WAKE_PHY; | ||
458 | if (opt & AX_MONITOR_MAGIC) | ||
459 | wolinfo->wolopts |= WAKE_MAGIC; | ||
460 | } | ||
461 | |||
462 | int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
463 | { | ||
464 | struct usbnet *dev = netdev_priv(net); | ||
465 | u8 opt = 0; | ||
466 | |||
467 | if (wolinfo->wolopts & WAKE_PHY) | ||
468 | opt |= AX_MONITOR_LINK; | ||
469 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
470 | opt |= AX_MONITOR_MAGIC; | ||
471 | |||
472 | if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | ||
473 | opt, 0, 0, NULL) < 0) | ||
474 | return -EINVAL; | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | int asix_get_eeprom_len(struct net_device *net) | ||
480 | { | ||
481 | return AX_EEPROM_LEN; | ||
482 | } | ||
483 | |||
484 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
485 | u8 *data) | ||
486 | { | ||
487 | struct usbnet *dev = netdev_priv(net); | ||
488 | u16 *eeprom_buff; | ||
489 | int first_word, last_word; | ||
490 | int i; | ||
491 | |||
492 | if (eeprom->len == 0) | ||
493 | return -EINVAL; | ||
494 | |||
495 | eeprom->magic = AX_EEPROM_MAGIC; | ||
496 | |||
497 | first_word = eeprom->offset >> 1; | ||
498 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | ||
499 | |||
500 | eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | ||
501 | GFP_KERNEL); | ||
502 | if (!eeprom_buff) | ||
503 | return -ENOMEM; | ||
504 | |||
505 | /* ax8817x returns 2 bytes from eeprom on read */ | ||
506 | for (i = first_word; i <= last_word; i++) { | ||
507 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2, | ||
508 | &(eeprom_buff[i - first_word])) < 0) { | ||
509 | kfree(eeprom_buff); | ||
510 | return -EIO; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); | ||
515 | kfree(eeprom_buff); | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
520 | u8 *data) | ||
521 | { | ||
522 | struct usbnet *dev = netdev_priv(net); | ||
523 | u16 *eeprom_buff; | ||
524 | int first_word, last_word; | ||
525 | int i; | ||
526 | int ret; | ||
527 | |||
528 | netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n", | ||
529 | eeprom->len, eeprom->offset, eeprom->magic); | ||
530 | |||
531 | if (eeprom->len == 0) | ||
532 | return -EINVAL; | ||
533 | |||
534 | if (eeprom->magic != AX_EEPROM_MAGIC) | ||
535 | return -EINVAL; | ||
536 | |||
537 | first_word = eeprom->offset >> 1; | ||
538 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | ||
539 | |||
540 | eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | ||
541 | GFP_KERNEL); | ||
542 | if (!eeprom_buff) | ||
543 | return -ENOMEM; | ||
544 | |||
545 | /* align data to 16 bit boundaries, read the missing data from | ||
546 | the EEPROM */ | ||
547 | if (eeprom->offset & 1) { | ||
548 | ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2, | ||
549 | &(eeprom_buff[0])); | ||
550 | if (ret < 0) { | ||
551 | netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); | ||
552 | goto free; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if ((eeprom->offset + eeprom->len) & 1) { | ||
557 | ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2, | ||
558 | &(eeprom_buff[last_word - first_word])); | ||
559 | if (ret < 0) { | ||
560 | netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); | ||
561 | goto free; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); | ||
566 | |||
567 | /* write data to EEPROM */ | ||
568 | ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL); | ||
569 | if (ret < 0) { | ||
570 | netdev_err(net, "Failed to enable EEPROM write\n"); | ||
571 | goto free; | ||
572 | } | ||
573 | msleep(20); | ||
574 | |||
575 | for (i = first_word; i <= last_word; i++) { | ||
576 | netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", | ||
577 | i, eeprom_buff[i - first_word]); | ||
578 | ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, | ||
579 | eeprom_buff[i - first_word], 0, NULL); | ||
580 | if (ret < 0) { | ||
581 | netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", | ||
582 | i); | ||
583 | goto free; | ||
584 | } | ||
585 | msleep(20); | ||
586 | } | ||
587 | |||
588 | ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL); | ||
589 | if (ret < 0) { | ||
590 | netdev_err(net, "Failed to disable EEPROM write\n"); | ||
591 | goto free; | ||
592 | } | ||
593 | |||
594 | ret = 0; | ||
595 | free: | ||
596 | kfree(eeprom_buff); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | ||
601 | { | ||
602 | /* Inherit standard device info */ | ||
603 | usbnet_get_drvinfo(net, info); | ||
604 | strncpy (info->driver, DRIVER_NAME, sizeof info->driver); | ||
605 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
606 | info->eedump_len = AX_EEPROM_LEN; | ||
607 | } | ||
608 | |||
609 | int asix_set_mac_address(struct net_device *net, void *p) | ||
610 | { | ||
611 | struct usbnet *dev = netdev_priv(net); | ||
612 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
613 | struct sockaddr *addr = p; | ||
614 | |||
615 | if (netif_running(net)) | ||
616 | return -EBUSY; | ||
617 | if (!is_valid_ether_addr(addr->sa_data)) | ||
618 | return -EADDRNOTAVAIL; | ||
619 | |||
620 | memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | ||
621 | |||
622 | /* We use the 20 byte dev->data | ||
623 | * for our 6 byte mac buffer | ||
624 | * to avoid allocating memory that | ||
625 | * is tricky to free later */ | ||
626 | memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | ||
627 | asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
628 | data->mac_addr); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix_devices.c index 3ae80eccd0ef..4fd48df6b989 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix_devices.c | |||
@@ -20,137 +20,7 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | // #define DEBUG // error path messages, extra info | 23 | #include "asix.h" |
24 | // #define VERBOSE // more; success messages | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/kmod.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/workqueue.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/usb.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/usb/usbnet.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/if_vlan.h> | ||
39 | |||
40 | #define DRIVER_VERSION "22-Dec-2011" | ||
41 | #define DRIVER_NAME "asix" | ||
42 | |||
43 | /* ASIX AX8817X based USB 2.0 Ethernet Devices */ | ||
44 | |||
45 | #define AX_CMD_SET_SW_MII 0x06 | ||
46 | #define AX_CMD_READ_MII_REG 0x07 | ||
47 | #define AX_CMD_WRITE_MII_REG 0x08 | ||
48 | #define AX_CMD_SET_HW_MII 0x0a | ||
49 | #define AX_CMD_READ_EEPROM 0x0b | ||
50 | #define AX_CMD_WRITE_EEPROM 0x0c | ||
51 | #define AX_CMD_WRITE_ENABLE 0x0d | ||
52 | #define AX_CMD_WRITE_DISABLE 0x0e | ||
53 | #define AX_CMD_READ_RX_CTL 0x0f | ||
54 | #define AX_CMD_WRITE_RX_CTL 0x10 | ||
55 | #define AX_CMD_READ_IPG012 0x11 | ||
56 | #define AX_CMD_WRITE_IPG0 0x12 | ||
57 | #define AX_CMD_WRITE_IPG1 0x13 | ||
58 | #define AX_CMD_READ_NODE_ID 0x13 | ||
59 | #define AX_CMD_WRITE_NODE_ID 0x14 | ||
60 | #define AX_CMD_WRITE_IPG2 0x14 | ||
61 | #define AX_CMD_WRITE_MULTI_FILTER 0x16 | ||
62 | #define AX88172_CMD_READ_NODE_ID 0x17 | ||
63 | #define AX_CMD_READ_PHY_ID 0x19 | ||
64 | #define AX_CMD_READ_MEDIUM_STATUS 0x1a | ||
65 | #define AX_CMD_WRITE_MEDIUM_MODE 0x1b | ||
66 | #define AX_CMD_READ_MONITOR_MODE 0x1c | ||
67 | #define AX_CMD_WRITE_MONITOR_MODE 0x1d | ||
68 | #define AX_CMD_READ_GPIOS 0x1e | ||
69 | #define AX_CMD_WRITE_GPIOS 0x1f | ||
70 | #define AX_CMD_SW_RESET 0x20 | ||
71 | #define AX_CMD_SW_PHY_STATUS 0x21 | ||
72 | #define AX_CMD_SW_PHY_SELECT 0x22 | ||
73 | |||
74 | #define AX_MONITOR_MODE 0x01 | ||
75 | #define AX_MONITOR_LINK 0x02 | ||
76 | #define AX_MONITOR_MAGIC 0x04 | ||
77 | #define AX_MONITOR_HSFS 0x10 | ||
78 | |||
79 | /* AX88172 Medium Status Register values */ | ||
80 | #define AX88172_MEDIUM_FD 0x02 | ||
81 | #define AX88172_MEDIUM_TX 0x04 | ||
82 | #define AX88172_MEDIUM_FC 0x10 | ||
83 | #define AX88172_MEDIUM_DEFAULT \ | ||
84 | ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | ||
85 | |||
86 | #define AX_MCAST_FILTER_SIZE 8 | ||
87 | #define AX_MAX_MCAST 64 | ||
88 | |||
89 | #define AX_SWRESET_CLEAR 0x00 | ||
90 | #define AX_SWRESET_RR 0x01 | ||
91 | #define AX_SWRESET_RT 0x02 | ||
92 | #define AX_SWRESET_PRTE 0x04 | ||
93 | #define AX_SWRESET_PRL 0x08 | ||
94 | #define AX_SWRESET_BZ 0x10 | ||
95 | #define AX_SWRESET_IPRL 0x20 | ||
96 | #define AX_SWRESET_IPPD 0x40 | ||
97 | |||
98 | #define AX88772_IPG0_DEFAULT 0x15 | ||
99 | #define AX88772_IPG1_DEFAULT 0x0c | ||
100 | #define AX88772_IPG2_DEFAULT 0x12 | ||
101 | |||
102 | /* AX88772 & AX88178 Medium Mode Register */ | ||
103 | #define AX_MEDIUM_PF 0x0080 | ||
104 | #define AX_MEDIUM_JFE 0x0040 | ||
105 | #define AX_MEDIUM_TFC 0x0020 | ||
106 | #define AX_MEDIUM_RFC 0x0010 | ||
107 | #define AX_MEDIUM_ENCK 0x0008 | ||
108 | #define AX_MEDIUM_AC 0x0004 | ||
109 | #define AX_MEDIUM_FD 0x0002 | ||
110 | #define AX_MEDIUM_GM 0x0001 | ||
111 | #define AX_MEDIUM_SM 0x1000 | ||
112 | #define AX_MEDIUM_SBP 0x0800 | ||
113 | #define AX_MEDIUM_PS 0x0200 | ||
114 | #define AX_MEDIUM_RE 0x0100 | ||
115 | |||
116 | #define AX88178_MEDIUM_DEFAULT \ | ||
117 | (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | ||
118 | AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | ||
119 | AX_MEDIUM_RE) | ||
120 | |||
121 | #define AX88772_MEDIUM_DEFAULT \ | ||
122 | (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | ||
123 | AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | ||
124 | AX_MEDIUM_AC | AX_MEDIUM_RE) | ||
125 | |||
126 | /* AX88772 & AX88178 RX_CTL values */ | ||
127 | #define AX_RX_CTL_SO 0x0080 | ||
128 | #define AX_RX_CTL_AP 0x0020 | ||
129 | #define AX_RX_CTL_AM 0x0010 | ||
130 | #define AX_RX_CTL_AB 0x0008 | ||
131 | #define AX_RX_CTL_SEP 0x0004 | ||
132 | #define AX_RX_CTL_AMALL 0x0002 | ||
133 | #define AX_RX_CTL_PRO 0x0001 | ||
134 | #define AX_RX_CTL_MFB_2048 0x0000 | ||
135 | #define AX_RX_CTL_MFB_4096 0x0100 | ||
136 | #define AX_RX_CTL_MFB_8192 0x0200 | ||
137 | #define AX_RX_CTL_MFB_16384 0x0300 | ||
138 | |||
139 | #define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) | ||
140 | |||
141 | /* GPIO 0 .. 2 toggles */ | ||
142 | #define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | ||
143 | #define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | ||
144 | #define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | ||
145 | #define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | ||
146 | #define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | ||
147 | #define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | ||
148 | #define AX_GPIO_RESERVED 0x40 /* Reserved */ | ||
149 | #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | ||
150 | |||
151 | #define AX_EEPROM_MAGIC 0xdeadbeef | ||
152 | #define AX88172_EEPROM_LEN 0x40 | ||
153 | #define AX88772_EEPROM_LEN 0xff | ||
154 | 24 | ||
155 | #define PHY_MODE_MARVELL 0x0000 | 25 | #define PHY_MODE_MARVELL 0x0000 |
156 | #define MII_MARVELL_LED_CTRL 0x0018 | 26 | #define MII_MARVELL_LED_CTRL 0x0018 |
@@ -166,15 +36,6 @@ | |||
166 | 36 | ||
167 | #define PHY_MODE_RTL8211CL 0x000C | 37 | #define PHY_MODE_RTL8211CL 0x000C |
168 | 38 | ||
169 | /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | ||
170 | struct asix_data { | ||
171 | u8 multi_filter[AX_MCAST_FILTER_SIZE]; | ||
172 | u8 mac_addr[ETH_ALEN]; | ||
173 | u8 phymode; | ||
174 | u8 ledmode; | ||
175 | u8 eeprom_len; | ||
176 | }; | ||
177 | |||
178 | struct ax88172_int_data { | 39 | struct ax88172_int_data { |
179 | __le16 res1; | 40 | __le16 res1; |
180 | u8 link; | 41 | u8 link; |
@@ -183,209 +44,6 @@ struct ax88172_int_data { | |||
183 | __le16 res3; | 44 | __le16 res3; |
184 | } __packed; | 45 | } __packed; |
185 | 46 | ||
186 | static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
187 | u16 size, void *data) | ||
188 | { | ||
189 | void *buf; | ||
190 | int err = -ENOMEM; | ||
191 | |||
192 | netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
193 | cmd, value, index, size); | ||
194 | |||
195 | buf = kmalloc(size, GFP_KERNEL); | ||
196 | if (!buf) | ||
197 | goto out; | ||
198 | |||
199 | err = usb_control_msg( | ||
200 | dev->udev, | ||
201 | usb_rcvctrlpipe(dev->udev, 0), | ||
202 | cmd, | ||
203 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
204 | value, | ||
205 | index, | ||
206 | buf, | ||
207 | size, | ||
208 | USB_CTRL_GET_TIMEOUT); | ||
209 | if (err == size) | ||
210 | memcpy(data, buf, size); | ||
211 | else if (err >= 0) | ||
212 | err = -EINVAL; | ||
213 | kfree(buf); | ||
214 | |||
215 | out: | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
220 | u16 size, void *data) | ||
221 | { | ||
222 | void *buf = NULL; | ||
223 | int err = -ENOMEM; | ||
224 | |||
225 | netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
226 | cmd, value, index, size); | ||
227 | |||
228 | if (data) { | ||
229 | buf = kmemdup(data, size, GFP_KERNEL); | ||
230 | if (!buf) | ||
231 | goto out; | ||
232 | } | ||
233 | |||
234 | err = usb_control_msg( | ||
235 | dev->udev, | ||
236 | usb_sndctrlpipe(dev->udev, 0), | ||
237 | cmd, | ||
238 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
239 | value, | ||
240 | index, | ||
241 | buf, | ||
242 | size, | ||
243 | USB_CTRL_SET_TIMEOUT); | ||
244 | kfree(buf); | ||
245 | |||
246 | out: | ||
247 | return err; | ||
248 | } | ||
249 | |||
250 | static void asix_async_cmd_callback(struct urb *urb) | ||
251 | { | ||
252 | struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | ||
253 | int status = urb->status; | ||
254 | |||
255 | if (status < 0) | ||
256 | printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", | ||
257 | status); | ||
258 | |||
259 | kfree(req); | ||
260 | usb_free_urb(urb); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | ||
265 | u16 size, void *data) | ||
266 | { | ||
267 | struct usb_ctrlrequest *req; | ||
268 | int status; | ||
269 | struct urb *urb; | ||
270 | |||
271 | netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", | ||
272 | cmd, value, index, size); | ||
273 | |||
274 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
275 | if (!urb) { | ||
276 | netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | ||
281 | if (!req) { | ||
282 | netdev_err(dev->net, "Failed to allocate memory for control request\n"); | ||
283 | usb_free_urb(urb); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | ||
288 | req->bRequest = cmd; | ||
289 | req->wValue = cpu_to_le16(value); | ||
290 | req->wIndex = cpu_to_le16(index); | ||
291 | req->wLength = cpu_to_le16(size); | ||
292 | |||
293 | usb_fill_control_urb(urb, dev->udev, | ||
294 | usb_sndctrlpipe(dev->udev, 0), | ||
295 | (void *)req, data, size, | ||
296 | asix_async_cmd_callback, req); | ||
297 | |||
298 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
299 | if (status < 0) { | ||
300 | netdev_err(dev->net, "Error submitting the control message: status=%d\n", | ||
301 | status); | ||
302 | kfree(req); | ||
303 | usb_free_urb(urb); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
308 | { | ||
309 | int offset = 0; | ||
310 | |||
311 | while (offset + sizeof(u32) < skb->len) { | ||
312 | struct sk_buff *ax_skb; | ||
313 | u16 size; | ||
314 | u32 header = get_unaligned_le32(skb->data + offset); | ||
315 | |||
316 | offset += sizeof(u32); | ||
317 | |||
318 | /* get the packet length */ | ||
319 | size = (u16) (header & 0x7ff); | ||
320 | if (size != ((~header >> 16) & 0x07ff)) { | ||
321 | netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | ||
326 | (size + offset > skb->len)) { | ||
327 | netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | ||
328 | size); | ||
329 | return 0; | ||
330 | } | ||
331 | ax_skb = netdev_alloc_skb_ip_align(dev->net, size); | ||
332 | if (!ax_skb) | ||
333 | return 0; | ||
334 | |||
335 | skb_put(ax_skb, size); | ||
336 | memcpy(ax_skb->data, skb->data + offset, size); | ||
337 | usbnet_skb_return(dev, ax_skb); | ||
338 | |||
339 | offset += (size + 1) & 0xfffe; | ||
340 | } | ||
341 | |||
342 | if (skb->len != offset) { | ||
343 | netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", | ||
344 | skb->len); | ||
345 | return 0; | ||
346 | } | ||
347 | return 1; | ||
348 | } | ||
349 | |||
350 | static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
351 | gfp_t flags) | ||
352 | { | ||
353 | int padlen; | ||
354 | int headroom = skb_headroom(skb); | ||
355 | int tailroom = skb_tailroom(skb); | ||
356 | u32 packet_len; | ||
357 | u32 padbytes = 0xffff0000; | ||
358 | |||
359 | padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | ||
360 | |||
361 | if ((!skb_cloned(skb)) && | ||
362 | ((headroom + tailroom) >= (4 + padlen))) { | ||
363 | if ((headroom < 4) || (tailroom < padlen)) { | ||
364 | skb->data = memmove(skb->head + 4, skb->data, skb->len); | ||
365 | skb_set_tail_pointer(skb, skb->len); | ||
366 | } | ||
367 | } else { | ||
368 | struct sk_buff *skb2; | ||
369 | skb2 = skb_copy_expand(skb, 4, padlen, flags); | ||
370 | dev_kfree_skb_any(skb); | ||
371 | skb = skb2; | ||
372 | if (!skb) | ||
373 | return NULL; | ||
374 | } | ||
375 | |||
376 | skb_push(skb, 4); | ||
377 | packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); | ||
378 | cpu_to_le32s(&packet_len); | ||
379 | skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | ||
380 | |||
381 | if (padlen) { | ||
382 | cpu_to_le32s(&padbytes); | ||
383 | memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | ||
384 | skb_put(skb, sizeof(padbytes)); | ||
385 | } | ||
386 | return skb; | ||
387 | } | ||
388 | |||
389 | static void asix_status(struct usbnet *dev, struct urb *urb) | 47 | static void asix_status(struct usbnet *dev, struct urb *urb) |
390 | { | 48 | { |
391 | struct ax88172_int_data *event; | 49 | struct ax88172_int_data *event; |
@@ -406,200 +64,6 @@ static void asix_status(struct usbnet *dev, struct urb *urb) | |||
406 | } | 64 | } |
407 | } | 65 | } |
408 | 66 | ||
409 | static inline int asix_set_sw_mii(struct usbnet *dev) | ||
410 | { | ||
411 | int ret; | ||
412 | ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | ||
413 | if (ret < 0) | ||
414 | netdev_err(dev->net, "Failed to enable software MII access\n"); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static inline int asix_set_hw_mii(struct usbnet *dev) | ||
419 | { | ||
420 | int ret; | ||
421 | ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | ||
422 | if (ret < 0) | ||
423 | netdev_err(dev->net, "Failed to enable hardware MII access\n"); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static inline int asix_get_phy_addr(struct usbnet *dev) | ||
428 | { | ||
429 | u8 buf[2]; | ||
430 | int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | ||
431 | |||
432 | netdev_dbg(dev->net, "asix_get_phy_addr()\n"); | ||
433 | |||
434 | if (ret < 0) { | ||
435 | netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); | ||
436 | goto out; | ||
437 | } | ||
438 | netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", | ||
439 | *((__le16 *)buf)); | ||
440 | ret = buf[1]; | ||
441 | |||
442 | out: | ||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | static int asix_sw_reset(struct usbnet *dev, u8 flags) | ||
447 | { | ||
448 | int ret; | ||
449 | |||
450 | ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | ||
451 | if (ret < 0) | ||
452 | netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); | ||
453 | |||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static u16 asix_read_rx_ctl(struct usbnet *dev) | ||
458 | { | ||
459 | __le16 v; | ||
460 | int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | ||
461 | |||
462 | if (ret < 0) { | ||
463 | netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); | ||
464 | goto out; | ||
465 | } | ||
466 | ret = le16_to_cpu(v); | ||
467 | out: | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | ||
472 | { | ||
473 | int ret; | ||
474 | |||
475 | netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); | ||
476 | ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | ||
477 | if (ret < 0) | ||
478 | netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", | ||
479 | mode, ret); | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static u16 asix_read_medium_status(struct usbnet *dev) | ||
485 | { | ||
486 | __le16 v; | ||
487 | int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | ||
488 | |||
489 | if (ret < 0) { | ||
490 | netdev_err(dev->net, "Error reading Medium Status register: %02x\n", | ||
491 | ret); | ||
492 | return ret; /* TODO: callers not checking for error ret */ | ||
493 | } | ||
494 | |||
495 | return le16_to_cpu(v); | ||
496 | |||
497 | } | ||
498 | |||
499 | static int asix_write_medium_mode(struct usbnet *dev, u16 mode) | ||
500 | { | ||
501 | int ret; | ||
502 | |||
503 | netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); | ||
504 | ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | ||
505 | if (ret < 0) | ||
506 | netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", | ||
507 | mode, ret); | ||
508 | |||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | ||
513 | { | ||
514 | int ret; | ||
515 | |||
516 | netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); | ||
517 | ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | ||
518 | if (ret < 0) | ||
519 | netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", | ||
520 | value, ret); | ||
521 | |||
522 | if (sleep) | ||
523 | msleep(sleep); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * AX88772 & AX88178 have a 16-bit RX_CTL value | ||
530 | */ | ||
531 | static void asix_set_multicast(struct net_device *net) | ||
532 | { | ||
533 | struct usbnet *dev = netdev_priv(net); | ||
534 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
535 | u16 rx_ctl = AX_DEFAULT_RX_CTL; | ||
536 | |||
537 | if (net->flags & IFF_PROMISC) { | ||
538 | rx_ctl |= AX_RX_CTL_PRO; | ||
539 | } else if (net->flags & IFF_ALLMULTI || | ||
540 | netdev_mc_count(net) > AX_MAX_MCAST) { | ||
541 | rx_ctl |= AX_RX_CTL_AMALL; | ||
542 | } else if (netdev_mc_empty(net)) { | ||
543 | /* just broadcast and directed */ | ||
544 | } else { | ||
545 | /* We use the 20 byte dev->data | ||
546 | * for our 8 byte filter buffer | ||
547 | * to avoid allocating memory that | ||
548 | * is tricky to free later */ | ||
549 | struct netdev_hw_addr *ha; | ||
550 | u32 crc_bits; | ||
551 | |||
552 | memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | ||
553 | |||
554 | /* Build the multicast hash filter. */ | ||
555 | netdev_for_each_mc_addr(ha, net) { | ||
556 | crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | ||
557 | data->multi_filter[crc_bits >> 3] |= | ||
558 | 1 << (crc_bits & 7); | ||
559 | } | ||
560 | |||
561 | asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | ||
562 | AX_MCAST_FILTER_SIZE, data->multi_filter); | ||
563 | |||
564 | rx_ctl |= AX_RX_CTL_AM; | ||
565 | } | ||
566 | |||
567 | asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | ||
568 | } | ||
569 | |||
570 | static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | ||
571 | { | ||
572 | struct usbnet *dev = netdev_priv(netdev); | ||
573 | __le16 res; | ||
574 | |||
575 | mutex_lock(&dev->phy_mutex); | ||
576 | asix_set_sw_mii(dev); | ||
577 | asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | ||
578 | (__u16)loc, 2, &res); | ||
579 | asix_set_hw_mii(dev); | ||
580 | mutex_unlock(&dev->phy_mutex); | ||
581 | |||
582 | netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | ||
583 | phy_id, loc, le16_to_cpu(res)); | ||
584 | |||
585 | return le16_to_cpu(res); | ||
586 | } | ||
587 | |||
588 | static void | ||
589 | asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | ||
590 | { | ||
591 | struct usbnet *dev = netdev_priv(netdev); | ||
592 | __le16 res = cpu_to_le16(val); | ||
593 | |||
594 | netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | ||
595 | phy_id, loc, val); | ||
596 | mutex_lock(&dev->phy_mutex); | ||
597 | asix_set_sw_mii(dev); | ||
598 | asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | ||
599 | asix_set_hw_mii(dev); | ||
600 | mutex_unlock(&dev->phy_mutex); | ||
601 | } | ||
602 | |||
603 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | 67 | /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ |
604 | static u32 asix_get_phyid(struct usbnet *dev) | 68 | static u32 asix_get_phyid(struct usbnet *dev) |
605 | { | 69 | { |
@@ -629,88 +93,6 @@ static u32 asix_get_phyid(struct usbnet *dev) | |||
629 | return phy_id; | 93 | return phy_id; |
630 | } | 94 | } |
631 | 95 | ||
632 | static void | ||
633 | asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
634 | { | ||
635 | struct usbnet *dev = netdev_priv(net); | ||
636 | u8 opt; | ||
637 | |||
638 | if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | ||
639 | wolinfo->supported = 0; | ||
640 | wolinfo->wolopts = 0; | ||
641 | return; | ||
642 | } | ||
643 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
644 | wolinfo->wolopts = 0; | ||
645 | if (opt & AX_MONITOR_LINK) | ||
646 | wolinfo->wolopts |= WAKE_PHY; | ||
647 | if (opt & AX_MONITOR_MAGIC) | ||
648 | wolinfo->wolopts |= WAKE_MAGIC; | ||
649 | } | ||
650 | |||
651 | static int | ||
652 | asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | ||
653 | { | ||
654 | struct usbnet *dev = netdev_priv(net); | ||
655 | u8 opt = 0; | ||
656 | |||
657 | if (wolinfo->wolopts & WAKE_PHY) | ||
658 | opt |= AX_MONITOR_LINK; | ||
659 | if (wolinfo->wolopts & WAKE_MAGIC) | ||
660 | opt |= AX_MONITOR_MAGIC; | ||
661 | |||
662 | if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | ||
663 | opt, 0, 0, NULL) < 0) | ||
664 | return -EINVAL; | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static int asix_get_eeprom_len(struct net_device *net) | ||
670 | { | ||
671 | struct usbnet *dev = netdev_priv(net); | ||
672 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
673 | |||
674 | return data->eeprom_len; | ||
675 | } | ||
676 | |||
677 | static int asix_get_eeprom(struct net_device *net, | ||
678 | struct ethtool_eeprom *eeprom, u8 *data) | ||
679 | { | ||
680 | struct usbnet *dev = netdev_priv(net); | ||
681 | __le16 *ebuf = (__le16 *)data; | ||
682 | int i; | ||
683 | |||
684 | /* Crude hack to ensure that we don't overwrite memory | ||
685 | * if an odd length is supplied | ||
686 | */ | ||
687 | if (eeprom->len % 2) | ||
688 | return -EINVAL; | ||
689 | |||
690 | eeprom->magic = AX_EEPROM_MAGIC; | ||
691 | |||
692 | /* ax8817x returns 2 bytes from eeprom on read */ | ||
693 | for (i=0; i < eeprom->len / 2; i++) { | ||
694 | if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, | ||
695 | eeprom->offset + i, 0, 2, &ebuf[i]) < 0) | ||
696 | return -EINVAL; | ||
697 | } | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static void asix_get_drvinfo (struct net_device *net, | ||
702 | struct ethtool_drvinfo *info) | ||
703 | { | ||
704 | struct usbnet *dev = netdev_priv(net); | ||
705 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
706 | |||
707 | /* Inherit standard device info */ | ||
708 | usbnet_get_drvinfo(net, info); | ||
709 | strncpy (info->driver, DRIVER_NAME, sizeof info->driver); | ||
710 | strncpy (info->version, DRIVER_VERSION, sizeof info->version); | ||
711 | info->eedump_len = data->eeprom_len; | ||
712 | } | ||
713 | |||
714 | static u32 asix_get_link(struct net_device *net) | 96 | static u32 asix_get_link(struct net_device *net) |
715 | { | 97 | { |
716 | struct usbnet *dev = netdev_priv(net); | 98 | struct usbnet *dev = netdev_priv(net); |
@@ -725,30 +107,6 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | |||
725 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | 107 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); |
726 | } | 108 | } |
727 | 109 | ||
728 | static int asix_set_mac_address(struct net_device *net, void *p) | ||
729 | { | ||
730 | struct usbnet *dev = netdev_priv(net); | ||
731 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
732 | struct sockaddr *addr = p; | ||
733 | |||
734 | if (netif_running(net)) | ||
735 | return -EBUSY; | ||
736 | if (!is_valid_ether_addr(addr->sa_data)) | ||
737 | return -EADDRNOTAVAIL; | ||
738 | |||
739 | memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | ||
740 | |||
741 | /* We use the 20 byte dev->data | ||
742 | * for our 6 byte mac buffer | ||
743 | * to avoid allocating memory that | ||
744 | * is tricky to free later */ | ||
745 | memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | ||
746 | asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
747 | data->mac_addr); | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | /* We need to override some ethtool_ops so we require our | 110 | /* We need to override some ethtool_ops so we require our |
753 | own structure so we don't interfere with other usbnet | 111 | own structure so we don't interfere with other usbnet |
754 | devices that may be connected at the same time. */ | 112 | devices that may be connected at the same time. */ |
@@ -761,6 +119,7 @@ static const struct ethtool_ops ax88172_ethtool_ops = { | |||
761 | .set_wol = asix_set_wol, | 119 | .set_wol = asix_set_wol, |
762 | .get_eeprom_len = asix_get_eeprom_len, | 120 | .get_eeprom_len = asix_get_eeprom_len, |
763 | .get_eeprom = asix_get_eeprom, | 121 | .get_eeprom = asix_get_eeprom, |
122 | .set_eeprom = asix_set_eeprom, | ||
764 | .get_settings = usbnet_get_settings, | 123 | .get_settings = usbnet_get_settings, |
765 | .set_settings = usbnet_set_settings, | 124 | .set_settings = usbnet_set_settings, |
766 | .nway_reset = usbnet_nway_reset, | 125 | .nway_reset = usbnet_nway_reset, |
@@ -843,9 +202,6 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | |||
843 | u8 buf[ETH_ALEN]; | 202 | u8 buf[ETH_ALEN]; |
844 | int i; | 203 | int i; |
845 | unsigned long gpio_bits = dev->driver_info->data; | 204 | unsigned long gpio_bits = dev->driver_info->data; |
846 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
847 | |||
848 | data->eeprom_len = AX88172_EEPROM_LEN; | ||
849 | 205 | ||
850 | usbnet_get_endpoints(dev,intf); | 206 | usbnet_get_endpoints(dev,intf); |
851 | 207 | ||
@@ -880,6 +236,8 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | |||
880 | 236 | ||
881 | dev->net->netdev_ops = &ax88172_netdev_ops; | 237 | dev->net->netdev_ops = &ax88172_netdev_ops; |
882 | dev->net->ethtool_ops = &ax88172_ethtool_ops; | 238 | dev->net->ethtool_ops = &ax88172_ethtool_ops; |
239 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
240 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
883 | 241 | ||
884 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | 242 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
885 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | 243 | asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
@@ -901,6 +259,7 @@ static const struct ethtool_ops ax88772_ethtool_ops = { | |||
901 | .set_wol = asix_set_wol, | 259 | .set_wol = asix_set_wol, |
902 | .get_eeprom_len = asix_get_eeprom_len, | 260 | .get_eeprom_len = asix_get_eeprom_len, |
903 | .get_eeprom = asix_get_eeprom, | 261 | .get_eeprom = asix_get_eeprom, |
262 | .set_eeprom = asix_set_eeprom, | ||
904 | .get_settings = usbnet_get_settings, | 263 | .get_settings = usbnet_get_settings, |
905 | .set_settings = usbnet_set_settings, | 264 | .set_settings = usbnet_set_settings, |
906 | .nway_reset = usbnet_nway_reset, | 265 | .nway_reset = usbnet_nway_reset, |
@@ -1049,12 +408,9 @@ static const struct net_device_ops ax88772_netdev_ops = { | |||
1049 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | 408 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) |
1050 | { | 409 | { |
1051 | int ret, embd_phy; | 410 | int ret, embd_phy; |
1052 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1053 | u8 buf[ETH_ALEN]; | 411 | u8 buf[ETH_ALEN]; |
1054 | u32 phyid; | 412 | u32 phyid; |
1055 | 413 | ||
1056 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1057 | |||
1058 | usbnet_get_endpoints(dev,intf); | 414 | usbnet_get_endpoints(dev,intf); |
1059 | 415 | ||
1060 | /* Get the MAC address */ | 416 | /* Get the MAC address */ |
@@ -1075,6 +431,8 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1075 | 431 | ||
1076 | dev->net->netdev_ops = &ax88772_netdev_ops; | 432 | dev->net->netdev_ops = &ax88772_netdev_ops; |
1077 | dev->net->ethtool_ops = &ax88772_ethtool_ops; | 433 | dev->net->ethtool_ops = &ax88772_ethtool_ops; |
434 | dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | ||
435 | dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | ||
1078 | 436 | ||
1079 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | 437 | embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); |
1080 | 438 | ||
@@ -1122,6 +480,7 @@ static const struct ethtool_ops ax88178_ethtool_ops = { | |||
1122 | .set_wol = asix_set_wol, | 480 | .set_wol = asix_set_wol, |
1123 | .get_eeprom_len = asix_get_eeprom_len, | 481 | .get_eeprom_len = asix_get_eeprom_len, |
1124 | .get_eeprom = asix_get_eeprom, | 482 | .get_eeprom = asix_get_eeprom, |
483 | .set_eeprom = asix_set_eeprom, | ||
1125 | .get_settings = usbnet_get_settings, | 484 | .get_settings = usbnet_get_settings, |
1126 | .set_settings = usbnet_set_settings, | 485 | .set_settings = usbnet_set_settings, |
1127 | .nway_reset = usbnet_nway_reset, | 486 | .nway_reset = usbnet_nway_reset, |
@@ -1405,9 +764,6 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1405 | { | 764 | { |
1406 | int ret; | 765 | int ret; |
1407 | u8 buf[ETH_ALEN]; | 766 | u8 buf[ETH_ALEN]; |
1408 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
1409 | |||
1410 | data->eeprom_len = AX88772_EEPROM_LEN; | ||
1411 | 767 | ||
1412 | usbnet_get_endpoints(dev,intf); | 768 | usbnet_get_endpoints(dev,intf); |
1413 | 769 | ||
@@ -1510,6 +866,8 @@ static const struct driver_info ax88178_info = { | |||
1510 | .tx_fixup = asix_tx_fixup, | 866 | .tx_fixup = asix_tx_fixup, |
1511 | }; | 867 | }; |
1512 | 868 | ||
869 | extern const struct driver_info ax88172a_info; | ||
870 | |||
1513 | static const struct usb_device_id products [] = { | 871 | static const struct usb_device_id products [] = { |
1514 | { | 872 | { |
1515 | // Linksys USB200M | 873 | // Linksys USB200M |
@@ -1635,6 +993,10 @@ static const struct usb_device_id products [] = { | |||
1635 | // Asus USB Ethernet Adapter | 993 | // Asus USB Ethernet Adapter |
1636 | USB_DEVICE (0x0b95, 0x7e2b), | 994 | USB_DEVICE (0x0b95, 0x7e2b), |
1637 | .driver_info = (unsigned long) &ax88772_info, | 995 | .driver_info = (unsigned long) &ax88772_info, |
996 | }, { | ||
997 | /* ASIX 88172a demo board */ | ||
998 | USB_DEVICE(0x0b95, 0x172a), | ||
999 | .driver_info = (unsigned long) &ax88172a_info, | ||
1638 | }, | 1000 | }, |
1639 | { }, // END | 1001 | { }, // END |
1640 | }; | 1002 | }; |
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c new file mode 100644 index 000000000000..c8e0aa85fb8e --- /dev/null +++ b/drivers/net/usb/ax88172a.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * ASIX AX88172A based USB 2.0 Ethernet Devices | ||
3 | * Copyright (C) 2012 OMICRON electronics GmbH | ||
4 | * | ||
5 | * Supports external PHYs via phylib. Based on the driver for the | ||
6 | * AX88772. Original copyrights follow: | ||
7 | * | ||
8 | * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | ||
9 | * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | ||
10 | * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | ||
11 | * Copyright (c) 2002-2003 TiVo Inc. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | #include "asix.h" | ||
29 | #include <linux/phy.h> | ||
30 | |||
31 | struct ax88172a_private { | ||
32 | struct mii_bus *mdio; | ||
33 | struct phy_device *phydev; | ||
34 | char phy_name[20]; | ||
35 | u16 phy_addr; | ||
36 | u16 oldmode; | ||
37 | int use_embdphy; | ||
38 | }; | ||
39 | |||
40 | /* MDIO read and write wrappers for phylib */ | ||
41 | static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum) | ||
42 | { | ||
43 | return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id, | ||
44 | regnum); | ||
45 | } | ||
46 | |||
47 | static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, | ||
48 | u16 val) | ||
49 | { | ||
50 | asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int ax88172a_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | ||
55 | { | ||
56 | if (!netif_running(net)) | ||
57 | return -EINVAL; | ||
58 | |||
59 | if (!net->phydev) | ||
60 | return -ENODEV; | ||
61 | |||
62 | return phy_mii_ioctl(net->phydev, rq, cmd); | ||
63 | } | ||
64 | |||
65 | /* set MAC link settings according to information from phylib */ | ||
66 | static void ax88172a_adjust_link(struct net_device *netdev) | ||
67 | { | ||
68 | struct phy_device *phydev = netdev->phydev; | ||
69 | struct usbnet *dev = netdev_priv(netdev); | ||
70 | struct ax88172a_private *priv = dev->driver_priv; | ||
71 | u16 mode = 0; | ||
72 | |||
73 | if (phydev->link) { | ||
74 | mode = AX88772_MEDIUM_DEFAULT; | ||
75 | |||
76 | if (phydev->duplex == DUPLEX_HALF) | ||
77 | mode &= ~AX_MEDIUM_FD; | ||
78 | |||
79 | if (phydev->speed != SPEED_100) | ||
80 | mode &= ~AX_MEDIUM_PS; | ||
81 | } | ||
82 | |||
83 | if (mode != priv->oldmode) { | ||
84 | asix_write_medium_mode(dev, mode); | ||
85 | priv->oldmode = mode; | ||
86 | netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n", | ||
87 | phydev->speed, phydev->duplex, mode); | ||
88 | phy_print_status(phydev); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void ax88172a_status(struct usbnet *dev, struct urb *urb) | ||
93 | { | ||
94 | /* link changes are detected by polling the phy */ | ||
95 | } | ||
96 | |||
97 | /* use phylib infrastructure */ | ||
98 | static int ax88172a_init_mdio(struct usbnet *dev) | ||
99 | { | ||
100 | struct ax88172a_private *priv = dev->driver_priv; | ||
101 | int ret, i; | ||
102 | |||
103 | priv->mdio = mdiobus_alloc(); | ||
104 | if (!priv->mdio) { | ||
105 | netdev_err(dev->net, "Could not allocate MDIO bus\n"); | ||
106 | return -ENOMEM; | ||
107 | } | ||
108 | |||
109 | priv->mdio->priv = (void *)dev; | ||
110 | priv->mdio->read = &asix_mdio_bus_read; | ||
111 | priv->mdio->write = &asix_mdio_bus_write; | ||
112 | priv->mdio->name = "Asix MDIO Bus"; | ||
113 | /* mii bus name is usb-<usb bus number>-<usb device number> */ | ||
114 | snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", | ||
115 | dev->udev->bus->busnum, dev->udev->devnum); | ||
116 | |||
117 | priv->mdio->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
118 | if (!priv->mdio->irq) { | ||
119 | netdev_err(dev->net, "Could not allocate mdio->irq\n"); | ||
120 | ret = -ENOMEM; | ||
121 | goto mfree; | ||
122 | } | ||
123 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
124 | priv->mdio->irq[i] = PHY_POLL; | ||
125 | |||
126 | ret = mdiobus_register(priv->mdio); | ||
127 | if (ret) { | ||
128 | netdev_err(dev->net, "Could not register MDIO bus\n"); | ||
129 | goto ifree; | ||
130 | } | ||
131 | |||
132 | netdev_info(dev->net, "registered mdio bus %s\n", priv->mdio->id); | ||
133 | return 0; | ||
134 | |||
135 | ifree: | ||
136 | kfree(priv->mdio->irq); | ||
137 | mfree: | ||
138 | mdiobus_free(priv->mdio); | ||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | static void ax88172a_remove_mdio(struct usbnet *dev) | ||
143 | { | ||
144 | struct ax88172a_private *priv = dev->driver_priv; | ||
145 | |||
146 | netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id); | ||
147 | mdiobus_unregister(priv->mdio); | ||
148 | kfree(priv->mdio->irq); | ||
149 | mdiobus_free(priv->mdio); | ||
150 | } | ||
151 | |||
152 | static const struct net_device_ops ax88172a_netdev_ops = { | ||
153 | .ndo_open = usbnet_open, | ||
154 | .ndo_stop = usbnet_stop, | ||
155 | .ndo_start_xmit = usbnet_start_xmit, | ||
156 | .ndo_tx_timeout = usbnet_tx_timeout, | ||
157 | .ndo_change_mtu = usbnet_change_mtu, | ||
158 | .ndo_set_mac_address = asix_set_mac_address, | ||
159 | .ndo_validate_addr = eth_validate_addr, | ||
160 | .ndo_do_ioctl = ax88172a_ioctl, | ||
161 | .ndo_set_rx_mode = asix_set_multicast, | ||
162 | }; | ||
163 | |||
164 | int ax88172a_get_settings(struct net_device *net, struct ethtool_cmd *cmd) | ||
165 | { | ||
166 | if (!net->phydev) | ||
167 | return -ENODEV; | ||
168 | |||
169 | return phy_ethtool_gset(net->phydev, cmd); | ||
170 | } | ||
171 | |||
172 | int ax88172a_set_settings(struct net_device *net, struct ethtool_cmd *cmd) | ||
173 | { | ||
174 | if (!net->phydev) | ||
175 | return -ENODEV; | ||
176 | |||
177 | return phy_ethtool_sset(net->phydev, cmd); | ||
178 | } | ||
179 | |||
180 | int ax88172a_nway_reset(struct net_device *net) | ||
181 | { | ||
182 | if (!net->phydev) | ||
183 | return -ENODEV; | ||
184 | |||
185 | return phy_start_aneg(net->phydev); | ||
186 | } | ||
187 | |||
188 | static const struct ethtool_ops ax88172a_ethtool_ops = { | ||
189 | .get_drvinfo = asix_get_drvinfo, | ||
190 | .get_link = usbnet_get_link, | ||
191 | .get_msglevel = usbnet_get_msglevel, | ||
192 | .set_msglevel = usbnet_set_msglevel, | ||
193 | .get_wol = asix_get_wol, | ||
194 | .set_wol = asix_set_wol, | ||
195 | .get_eeprom_len = asix_get_eeprom_len, | ||
196 | .get_eeprom = asix_get_eeprom, | ||
197 | .set_eeprom = asix_set_eeprom, | ||
198 | .get_settings = ax88172a_get_settings, | ||
199 | .set_settings = ax88172a_set_settings, | ||
200 | .nway_reset = ax88172a_nway_reset, | ||
201 | }; | ||
202 | |||
203 | static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy) | ||
204 | { | ||
205 | int ret; | ||
206 | |||
207 | ret = asix_sw_reset(dev, AX_SWRESET_IPPD); | ||
208 | if (ret < 0) | ||
209 | goto err; | ||
210 | |||
211 | msleep(150); | ||
212 | ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | ||
213 | if (ret < 0) | ||
214 | goto err; | ||
215 | |||
216 | msleep(150); | ||
217 | |||
218 | ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD); | ||
219 | if (ret < 0) | ||
220 | goto err; | ||
221 | |||
222 | return 0; | ||
223 | |||
224 | err: | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | |||
229 | static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) | ||
230 | { | ||
231 | int ret; | ||
232 | u8 buf[ETH_ALEN]; | ||
233 | struct ax88172a_private *priv; | ||
234 | |||
235 | usbnet_get_endpoints(dev, intf); | ||
236 | |||
237 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
238 | if (!priv) { | ||
239 | netdev_err(dev->net, "Could not allocate memory for private data\n"); | ||
240 | return -ENOMEM; | ||
241 | } | ||
242 | dev->driver_priv = priv; | ||
243 | |||
244 | /* Get the MAC address */ | ||
245 | ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | ||
246 | if (ret < 0) { | ||
247 | netdev_err(dev->net, "Failed to read MAC address: %d\n", ret); | ||
248 | goto free; | ||
249 | } | ||
250 | memcpy(dev->net->dev_addr, buf, ETH_ALEN); | ||
251 | |||
252 | dev->net->netdev_ops = &ax88172a_netdev_ops; | ||
253 | dev->net->ethtool_ops = &ax88172a_ethtool_ops; | ||
254 | |||
255 | /* are we using the internal or the external phy? */ | ||
256 | ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf); | ||
257 | if (ret < 0) { | ||
258 | netdev_err(dev->net, "Failed to read software interface selection register: %d\n", | ||
259 | ret); | ||
260 | goto free; | ||
261 | } | ||
262 | |||
263 | netdev_dbg(dev->net, "AX_CMD_SW_PHY_STATUS = 0x%02x\n", buf[0]); | ||
264 | switch (buf[0] & AX_PHY_SELECT_MASK) { | ||
265 | case AX_PHY_SELECT_INTERNAL: | ||
266 | netdev_dbg(dev->net, "use internal phy\n"); | ||
267 | priv->use_embdphy = 1; | ||
268 | break; | ||
269 | case AX_PHY_SELECT_EXTERNAL: | ||
270 | netdev_dbg(dev->net, "use external phy\n"); | ||
271 | priv->use_embdphy = 0; | ||
272 | break; | ||
273 | default: | ||
274 | netdev_err(dev->net, "Interface mode not supported by driver\n"); | ||
275 | ret = -ENOTSUPP; | ||
276 | goto free; | ||
277 | } | ||
278 | |||
279 | priv->phy_addr = asix_read_phy_addr(dev, priv->use_embdphy); | ||
280 | ax88172a_reset_phy(dev, priv->use_embdphy); | ||
281 | |||
282 | /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | ||
283 | if (dev->driver_info->flags & FLAG_FRAMING_AX) { | ||
284 | /* hard_mtu is still the default - the device does not support | ||
285 | jumbo eth frames */ | ||
286 | dev->rx_urb_size = 2048; | ||
287 | } | ||
288 | |||
289 | /* init MDIO bus */ | ||
290 | ret = ax88172a_init_mdio(dev); | ||
291 | if (ret) | ||
292 | goto free; | ||
293 | |||
294 | return 0; | ||
295 | |||
296 | free: | ||
297 | kfree(priv); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int ax88172a_stop(struct usbnet *dev) | ||
302 | { | ||
303 | struct ax88172a_private *priv = dev->driver_priv; | ||
304 | |||
305 | netdev_dbg(dev->net, "Stopping interface\n"); | ||
306 | |||
307 | if (priv->phydev) { | ||
308 | netdev_info(dev->net, "Disconnecting from phy %s\n", | ||
309 | priv->phy_name); | ||
310 | phy_stop(priv->phydev); | ||
311 | phy_disconnect(priv->phydev); | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void ax88172a_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
318 | { | ||
319 | struct ax88172a_private *priv = dev->driver_priv; | ||
320 | |||
321 | ax88172a_remove_mdio(dev); | ||
322 | kfree(priv); | ||
323 | } | ||
324 | |||
325 | static int ax88172a_reset(struct usbnet *dev) | ||
326 | { | ||
327 | struct asix_data *data = (struct asix_data *)&dev->data; | ||
328 | struct ax88172a_private *priv = dev->driver_priv; | ||
329 | int ret; | ||
330 | u16 rx_ctl; | ||
331 | |||
332 | ax88172a_reset_phy(dev, priv->use_embdphy); | ||
333 | |||
334 | msleep(150); | ||
335 | rx_ctl = asix_read_rx_ctl(dev); | ||
336 | netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | ||
337 | ret = asix_write_rx_ctl(dev, 0x0000); | ||
338 | if (ret < 0) | ||
339 | goto out; | ||
340 | |||
341 | rx_ctl = asix_read_rx_ctl(dev); | ||
342 | netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | ||
343 | |||
344 | msleep(150); | ||
345 | |||
346 | ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | ||
347 | AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | ||
348 | AX88772_IPG2_DEFAULT, 0, NULL); | ||
349 | if (ret < 0) { | ||
350 | netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | /* Rewrite MAC address */ | ||
355 | memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | ||
356 | ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | ||
357 | data->mac_addr); | ||
358 | if (ret < 0) | ||
359 | goto out; | ||
360 | |||
361 | /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | ||
362 | ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | ||
363 | if (ret < 0) | ||
364 | goto out; | ||
365 | |||
366 | rx_ctl = asix_read_rx_ctl(dev); | ||
367 | netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", | ||
368 | rx_ctl); | ||
369 | |||
370 | rx_ctl = asix_read_medium_status(dev); | ||
371 | netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n", | ||
372 | rx_ctl); | ||
373 | |||
374 | /* Connect to PHY */ | ||
375 | snprintf(priv->phy_name, 20, PHY_ID_FMT, | ||
376 | priv->mdio->id, priv->phy_addr); | ||
377 | |||
378 | priv->phydev = phy_connect(dev->net, priv->phy_name, | ||
379 | &ax88172a_adjust_link, | ||
380 | 0, PHY_INTERFACE_MODE_MII); | ||
381 | if (IS_ERR(priv->phydev)) { | ||
382 | netdev_err(dev->net, "Could not connect to PHY device %s\n", | ||
383 | priv->phy_name); | ||
384 | ret = PTR_ERR(priv->phydev); | ||
385 | goto out; | ||
386 | } | ||
387 | |||
388 | netdev_info(dev->net, "Connected to phy %s\n", priv->phy_name); | ||
389 | |||
390 | /* During power-up, the AX88172A set the power down (BMCR_PDOWN) | ||
391 | * bit of the PHY. Bring the PHY up again. | ||
392 | */ | ||
393 | genphy_resume(priv->phydev); | ||
394 | phy_start(priv->phydev); | ||
395 | |||
396 | return 0; | ||
397 | |||
398 | out: | ||
399 | return ret; | ||
400 | |||
401 | } | ||
402 | |||
403 | const struct driver_info ax88172a_info = { | ||
404 | .description = "ASIX AX88172A USB 2.0 Ethernet", | ||
405 | .bind = ax88172a_bind, | ||
406 | .reset = ax88172a_reset, | ||
407 | .stop = ax88172a_stop, | ||
408 | .unbind = ax88172a_unbind, | ||
409 | .status = ax88172a_status, | ||
410 | .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | ||
411 | FLAG_MULTI_PACKET, | ||
412 | .rx_fixup = asix_rx_fixup, | ||
413 | .tx_fixup = asix_tx_fixup, | ||
414 | }; | ||
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index d848d4dd5754..64610048ce87 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c | |||
@@ -130,7 +130,7 @@ static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags) | |||
130 | struct page *page; | 130 | struct page *page; |
131 | int err; | 131 | int err; |
132 | 132 | ||
133 | page = alloc_page(gfp_flags); | 133 | page = __skb_alloc_page(gfp_flags | __GFP_NOMEMALLOC, NULL); |
134 | if (!page) | 134 | if (!page) |
135 | return -ENOMEM; | 135 | return -ENOMEM; |
136 | 136 | ||
@@ -394,7 +394,7 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
394 | SET_NETDEV_DEV(dev, &intf->dev); | 394 | SET_NETDEV_DEV(dev, &intf->dev); |
395 | 395 | ||
396 | pnd->dev = dev; | 396 | pnd->dev = dev; |
397 | pnd->usb = usb_get_dev(usbdev); | 397 | pnd->usb = usbdev; |
398 | pnd->intf = intf; | 398 | pnd->intf = intf; |
399 | pnd->data_intf = data_intf; | 399 | pnd->data_intf = data_intf; |
400 | spin_lock_init(&pnd->tx_lock); | 400 | spin_lock_init(&pnd->tx_lock); |
@@ -440,7 +440,6 @@ out: | |||
440 | static void usbpn_disconnect(struct usb_interface *intf) | 440 | static void usbpn_disconnect(struct usb_interface *intf) |
441 | { | 441 | { |
442 | struct usbpn_dev *pnd = usb_get_intfdata(intf); | 442 | struct usbpn_dev *pnd = usb_get_intfdata(intf); |
443 | struct usb_device *usb = pnd->usb; | ||
444 | 443 | ||
445 | if (pnd->disconnected) | 444 | if (pnd->disconnected) |
446 | return; | 445 | return; |
@@ -449,7 +448,6 @@ static void usbpn_disconnect(struct usb_interface *intf) | |||
449 | usb_driver_release_interface(&usbpn_driver, | 448 | usb_driver_release_interface(&usbpn_driver, |
450 | (pnd->intf == intf) ? pnd->data_intf : pnd->intf); | 449 | (pnd->intf == intf) ? pnd->data_intf : pnd->intf); |
451 | unregister_netdev(pnd->dev); | 450 | unregister_netdev(pnd->dev); |
452 | usb_put_dev(usb); | ||
453 | } | 451 | } |
454 | 452 | ||
455 | static struct usb_driver usbpn_driver = { | 453 | static struct usb_driver usbpn_driver = { |
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 4b9513fcf275..f4ce5957df32 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c | |||
@@ -138,20 +138,7 @@ struct cdc_ncm_ctx { | |||
138 | static void cdc_ncm_txpath_bh(unsigned long param); | 138 | static void cdc_ncm_txpath_bh(unsigned long param); |
139 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); | 139 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx); |
140 | static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); | 140 | static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); |
141 | static const struct driver_info cdc_ncm_info; | ||
142 | static struct usb_driver cdc_ncm_driver; | 141 | static struct usb_driver cdc_ncm_driver; |
143 | static const struct ethtool_ops cdc_ncm_ethtool_ops; | ||
144 | |||
145 | static const struct usb_device_id cdc_devs[] = { | ||
146 | { USB_INTERFACE_INFO(USB_CLASS_COMM, | ||
147 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | ||
148 | .driver_info = (unsigned long)&cdc_ncm_info, | ||
149 | }, | ||
150 | { | ||
151 | }, | ||
152 | }; | ||
153 | |||
154 | MODULE_DEVICE_TABLE(usb, cdc_devs); | ||
155 | 142 | ||
156 | static void | 143 | static void |
157 | cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | 144 | cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) |
@@ -454,6 +441,16 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) | |||
454 | kfree(ctx); | 441 | kfree(ctx); |
455 | } | 442 | } |
456 | 443 | ||
444 | static const struct ethtool_ops cdc_ncm_ethtool_ops = { | ||
445 | .get_drvinfo = cdc_ncm_get_drvinfo, | ||
446 | .get_link = usbnet_get_link, | ||
447 | .get_msglevel = usbnet_get_msglevel, | ||
448 | .set_msglevel = usbnet_set_msglevel, | ||
449 | .get_settings = usbnet_get_settings, | ||
450 | .set_settings = usbnet_set_settings, | ||
451 | .nway_reset = usbnet_nway_reset, | ||
452 | }; | ||
453 | |||
457 | static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) | 454 | static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) |
458 | { | 455 | { |
459 | struct cdc_ncm_ctx *ctx; | 456 | struct cdc_ncm_ctx *ctx; |
@@ -1203,6 +1200,41 @@ static const struct driver_info cdc_ncm_info = { | |||
1203 | .tx_fixup = cdc_ncm_tx_fixup, | 1200 | .tx_fixup = cdc_ncm_tx_fixup, |
1204 | }; | 1201 | }; |
1205 | 1202 | ||
1203 | /* Same as cdc_ncm_info, but with FLAG_WWAN */ | ||
1204 | static const struct driver_info wwan_info = { | ||
1205 | .description = "Mobile Broadband Network Device", | ||
1206 | .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET | ||
1207 | | FLAG_WWAN, | ||
1208 | .bind = cdc_ncm_bind, | ||
1209 | .unbind = cdc_ncm_unbind, | ||
1210 | .check_connect = cdc_ncm_check_connect, | ||
1211 | .manage_power = cdc_ncm_manage_power, | ||
1212 | .status = cdc_ncm_status, | ||
1213 | .rx_fixup = cdc_ncm_rx_fixup, | ||
1214 | .tx_fixup = cdc_ncm_tx_fixup, | ||
1215 | }; | ||
1216 | |||
1217 | static const struct usb_device_id cdc_devs[] = { | ||
1218 | /* Ericsson MBM devices like F5521gw */ | ||
1219 | { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
1220 | | USB_DEVICE_ID_MATCH_VENDOR, | ||
1221 | .idVendor = 0x0bdb, | ||
1222 | .bInterfaceClass = USB_CLASS_COMM, | ||
1223 | .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, | ||
1224 | .bInterfaceProtocol = USB_CDC_PROTO_NONE, | ||
1225 | .driver_info = (unsigned long) &wwan_info, | ||
1226 | }, | ||
1227 | |||
1228 | /* Generic CDC-NCM devices */ | ||
1229 | { USB_INTERFACE_INFO(USB_CLASS_COMM, | ||
1230 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | ||
1231 | .driver_info = (unsigned long)&cdc_ncm_info, | ||
1232 | }, | ||
1233 | { | ||
1234 | }, | ||
1235 | }; | ||
1236 | MODULE_DEVICE_TABLE(usb, cdc_devs); | ||
1237 | |||
1206 | static struct usb_driver cdc_ncm_driver = { | 1238 | static struct usb_driver cdc_ncm_driver = { |
1207 | .name = "cdc_ncm", | 1239 | .name = "cdc_ncm", |
1208 | .id_table = cdc_devs, | 1240 | .id_table = cdc_devs, |
@@ -1215,16 +1247,6 @@ static struct usb_driver cdc_ncm_driver = { | |||
1215 | .disable_hub_initiated_lpm = 1, | 1247 | .disable_hub_initiated_lpm = 1, |
1216 | }; | 1248 | }; |
1217 | 1249 | ||
1218 | static const struct ethtool_ops cdc_ncm_ethtool_ops = { | ||
1219 | .get_drvinfo = cdc_ncm_get_drvinfo, | ||
1220 | .get_link = usbnet_get_link, | ||
1221 | .get_msglevel = usbnet_get_msglevel, | ||
1222 | .set_msglevel = usbnet_set_msglevel, | ||
1223 | .get_settings = usbnet_get_settings, | ||
1224 | .set_settings = usbnet_set_settings, | ||
1225 | .nway_reset = usbnet_nway_reset, | ||
1226 | }; | ||
1227 | |||
1228 | module_usb_driver(cdc_ncm_driver); | 1250 | module_usb_driver(cdc_ncm_driver); |
1229 | 1251 | ||
1230 | MODULE_AUTHOR("Hans Petter Selasky"); | 1252 | MODULE_AUTHOR("Hans Petter Selasky"); |
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index d8ad55284389..c3d03490c97d 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c | |||
@@ -1314,7 +1314,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |||
1314 | int retv; | 1314 | int retv; |
1315 | int length = 0; /* shut up GCC */ | 1315 | int length = 0; /* shut up GCC */ |
1316 | 1316 | ||
1317 | urb = usb_alloc_urb(0, GFP_NOIO); | 1317 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
1318 | if (!urb) | 1318 | if (!urb) |
1319 | return -ENOMEM; | 1319 | return -ENOMEM; |
1320 | 1320 | ||
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 7023220456c5..a0b5807b30d4 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c | |||
@@ -1329,8 +1329,6 @@ static int pegasus_probe(struct usb_interface *intf, | |||
1329 | } | 1329 | } |
1330 | pegasus_count++; | 1330 | pegasus_count++; |
1331 | 1331 | ||
1332 | usb_get_dev(dev); | ||
1333 | |||
1334 | net = alloc_etherdev(sizeof(struct pegasus)); | 1332 | net = alloc_etherdev(sizeof(struct pegasus)); |
1335 | if (!net) | 1333 | if (!net) |
1336 | goto out; | 1334 | goto out; |
@@ -1407,7 +1405,6 @@ out2: | |||
1407 | out1: | 1405 | out1: |
1408 | free_netdev(net); | 1406 | free_netdev(net); |
1409 | out: | 1407 | out: |
1410 | usb_put_dev(dev); | ||
1411 | pegasus_dec_workqueue(); | 1408 | pegasus_dec_workqueue(); |
1412 | return res; | 1409 | return res; |
1413 | } | 1410 | } |
@@ -1425,7 +1422,6 @@ static void pegasus_disconnect(struct usb_interface *intf) | |||
1425 | pegasus->flags |= PEGASUS_UNPLUG; | 1422 | pegasus->flags |= PEGASUS_UNPLUG; |
1426 | cancel_delayed_work(&pegasus->carrier_check); | 1423 | cancel_delayed_work(&pegasus->carrier_check); |
1427 | unregister_netdev(pegasus->net); | 1424 | unregister_netdev(pegasus->net); |
1428 | usb_put_dev(interface_to_usbdev(intf)); | ||
1429 | unlink_all_urbs(pegasus); | 1425 | unlink_all_urbs(pegasus); |
1430 | free_all_urbs(pegasus); | 1426 | free_all_urbs(pegasus); |
1431 | free_skb_pool(pegasus); | 1427 | free_skb_pool(pegasus); |
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index b01960fcfbc9..2ea126a16d79 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c | |||
@@ -1,6 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> | 2 | * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> |
3 | * | 3 | * |
4 | * The probing code is heavily inspired by cdc_ether, which is: | ||
5 | * Copyright (C) 2003-2005 by David Brownell | ||
6 | * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) | ||
7 | * | ||
4 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 9 | * modify it under the terms of the GNU General Public License |
6 | * version 2 as published by the Free Software Foundation. | 10 | * version 2 as published by the Free Software Foundation. |
@@ -15,11 +19,7 @@ | |||
15 | #include <linux/usb/usbnet.h> | 19 | #include <linux/usb/usbnet.h> |
16 | #include <linux/usb/cdc-wdm.h> | 20 | #include <linux/usb/cdc-wdm.h> |
17 | 21 | ||
18 | /* The name of the CDC Device Management driver */ | 22 | /* This driver supports wwan (3G/LTE/?) devices using a vendor |
19 | #define DM_DRIVER "cdc_wdm" | ||
20 | |||
21 | /* | ||
22 | * This driver supports wwan (3G/LTE/?) devices using a vendor | ||
23 | * specific management protocol called Qualcomm MSM Interface (QMI) - | 23 | * specific management protocol called Qualcomm MSM Interface (QMI) - |
24 | * in addition to the more common AT commands over serial interface | 24 | * in addition to the more common AT commands over serial interface |
25 | * management | 25 | * management |
@@ -31,59 +31,117 @@ | |||
31 | * management protocol is used in place of the standard CDC | 31 | * management protocol is used in place of the standard CDC |
32 | * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE | 32 | * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE |
33 | * | 33 | * |
34 | * Alternatively, control and data functions can be combined in a | ||
35 | * single USB interface. | ||
36 | * | ||
34 | * Handling a protocol like QMI is out of the scope for any driver. | 37 | * Handling a protocol like QMI is out of the scope for any driver. |
35 | * It can be exported as a character device using the cdc-wdm driver, | 38 | * It is exported as a character device using the cdc-wdm driver as |
36 | * which will enable userspace applications ("modem managers") to | 39 | * a subdriver, enabling userspace applications ("modem managers") to |
37 | * handle it. This may be required to use the network interface | 40 | * handle it. |
38 | * provided by the driver. | ||
39 | * | 41 | * |
40 | * These devices may alternatively/additionally be configured using AT | 42 | * These devices may alternatively/additionally be configured using AT |
41 | * commands on any of the serial interfaces driven by the option driver | 43 | * commands on a serial interface |
42 | * | ||
43 | * This driver binds only to the data ("slave") interface to enable | ||
44 | * the cdc-wdm driver to bind to the control interface. It still | ||
45 | * parses the CDC functional descriptors on the control interface to | ||
46 | * a) verify that this is indeed a handled interface (CDC Union | ||
47 | * header lists it as slave) | ||
48 | * b) get MAC address and other ethernet config from the CDC Ethernet | ||
49 | * header | ||
50 | * c) enable user bind requests against the control interface, which | ||
51 | * is the common way to bind to CDC Ethernet Control Model type | ||
52 | * interfaces | ||
53 | * d) provide a hint to the user about which interface is the | ||
54 | * corresponding management interface | ||
55 | */ | 44 | */ |
56 | 45 | ||
46 | /* driver specific data */ | ||
47 | struct qmi_wwan_state { | ||
48 | struct usb_driver *subdriver; | ||
49 | atomic_t pmcount; | ||
50 | unsigned long unused; | ||
51 | struct usb_interface *control; | ||
52 | struct usb_interface *data; | ||
53 | }; | ||
54 | |||
55 | /* using a counter to merge subdriver requests with our own into a combined state */ | ||
56 | static int qmi_wwan_manage_power(struct usbnet *dev, int on) | ||
57 | { | ||
58 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
59 | int rv = 0; | ||
60 | |||
61 | dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(&info->pmcount), on); | ||
62 | |||
63 | if ((on && atomic_add_return(1, &info->pmcount) == 1) || (!on && atomic_dec_and_test(&info->pmcount))) { | ||
64 | /* need autopm_get/put here to ensure the usbcore sees the new value */ | ||
65 | rv = usb_autopm_get_interface(dev->intf); | ||
66 | if (rv < 0) | ||
67 | goto err; | ||
68 | dev->intf->needs_remote_wakeup = on; | ||
69 | usb_autopm_put_interface(dev->intf); | ||
70 | } | ||
71 | err: | ||
72 | return rv; | ||
73 | } | ||
74 | |||
75 | static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) | ||
76 | { | ||
77 | struct usbnet *dev = usb_get_intfdata(intf); | ||
78 | |||
79 | /* can be called while disconnecting */ | ||
80 | if (!dev) | ||
81 | return 0; | ||
82 | return qmi_wwan_manage_power(dev, on); | ||
83 | } | ||
84 | |||
85 | /* collect all three endpoints and register subdriver */ | ||
86 | static int qmi_wwan_register_subdriver(struct usbnet *dev) | ||
87 | { | ||
88 | int rv; | ||
89 | struct usb_driver *subdriver = NULL; | ||
90 | struct qmi_wwan_state *info = (void *)&dev->data; | ||
91 | |||
92 | /* collect bulk endpoints */ | ||
93 | rv = usbnet_get_endpoints(dev, info->data); | ||
94 | if (rv < 0) | ||
95 | goto err; | ||
96 | |||
97 | /* update status endpoint if separate control interface */ | ||
98 | if (info->control != info->data) | ||
99 | dev->status = &info->control->cur_altsetting->endpoint[0]; | ||
100 | |||
101 | /* require interrupt endpoint for subdriver */ | ||
102 | if (!dev->status) { | ||
103 | rv = -EINVAL; | ||
104 | goto err; | ||
105 | } | ||
106 | |||
107 | /* for subdriver power management */ | ||
108 | atomic_set(&info->pmcount, 0); | ||
109 | |||
110 | /* register subdriver */ | ||
111 | subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); | ||
112 | if (IS_ERR(subdriver)) { | ||
113 | dev_err(&info->control->dev, "subdriver registration failed\n"); | ||
114 | rv = PTR_ERR(subdriver); | ||
115 | goto err; | ||
116 | } | ||
117 | |||
118 | /* prevent usbnet from using status endpoint */ | ||
119 | dev->status = NULL; | ||
120 | |||
121 | /* save subdriver struct for suspend/resume wrappers */ | ||
122 | info->subdriver = subdriver; | ||
123 | |||
124 | err: | ||
125 | return rv; | ||
126 | } | ||
127 | |||
57 | static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) | 128 | static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) |
58 | { | 129 | { |
59 | int status = -1; | 130 | int status = -1; |
60 | struct usb_interface *control = NULL; | ||
61 | u8 *buf = intf->cur_altsetting->extra; | 131 | u8 *buf = intf->cur_altsetting->extra; |
62 | int len = intf->cur_altsetting->extralen; | 132 | int len = intf->cur_altsetting->extralen; |
63 | struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; | 133 | struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; |
64 | struct usb_cdc_union_desc *cdc_union = NULL; | 134 | struct usb_cdc_union_desc *cdc_union = NULL; |
65 | struct usb_cdc_ether_desc *cdc_ether = NULL; | 135 | struct usb_cdc_ether_desc *cdc_ether = NULL; |
66 | u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE; | ||
67 | u32 found = 0; | 136 | u32 found = 0; |
68 | atomic_t *pmcount = (void *)&dev->data[1]; | 137 | struct usb_driver *driver = driver_of(intf); |
69 | 138 | struct qmi_wwan_state *info = (void *)&dev->data; | |
70 | atomic_set(pmcount, 0); | ||
71 | 139 | ||
72 | /* | 140 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state))); |
73 | * assume a data interface has no additional descriptors and | ||
74 | * that the control and data interface are numbered | ||
75 | * consecutively - this holds for the Huawei device at least | ||
76 | */ | ||
77 | if (len == 0 && desc->bInterfaceNumber > 0) { | ||
78 | control = usb_ifnum_to_if(dev->udev, desc->bInterfaceNumber - 1); | ||
79 | if (!control) | ||
80 | goto err; | ||
81 | 141 | ||
82 | buf = control->cur_altsetting->extra; | 142 | /* require a single interrupt status endpoint for subdriver */ |
83 | len = control->cur_altsetting->extralen; | 143 | if (intf->cur_altsetting->desc.bNumEndpoints != 1) |
84 | dev_dbg(&intf->dev, "guessing \"control\" => %s, \"data\" => this\n", | 144 | goto err; |
85 | dev_name(&control->dev)); | ||
86 | } | ||
87 | 145 | ||
88 | while (len > 3) { | 146 | while (len > 3) { |
89 | struct usb_descriptor_header *h = (void *)buf; | 147 | struct usb_descriptor_header *h = (void *)buf; |
@@ -142,15 +200,23 @@ next_desc: | |||
142 | } | 200 | } |
143 | 201 | ||
144 | /* did we find all the required ones? */ | 202 | /* did we find all the required ones? */ |
145 | if ((found & required) != required) { | 203 | if (!(found & (1 << USB_CDC_HEADER_TYPE)) || |
204 | !(found & (1 << USB_CDC_UNION_TYPE))) { | ||
146 | dev_err(&intf->dev, "CDC functional descriptors missing\n"); | 205 | dev_err(&intf->dev, "CDC functional descriptors missing\n"); |
147 | goto err; | 206 | goto err; |
148 | } | 207 | } |
149 | 208 | ||
150 | /* give the user a helpful hint if trying to bind to the wrong interface */ | 209 | /* verify CDC Union */ |
151 | if (cdc_union && desc->bInterfaceNumber == cdc_union->bMasterInterface0) { | 210 | if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) { |
152 | dev_err(&intf->dev, "leaving \"control\" interface for " DM_DRIVER " - try binding to %s instead!\n", | 211 | dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0); |
153 | dev_name(&usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0)->dev)); | 212 | goto err; |
213 | } | ||
214 | |||
215 | /* need to save these for unbind */ | ||
216 | info->control = intf; | ||
217 | info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0); | ||
218 | if (!info->data) { | ||
219 | dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0); | ||
154 | goto err; | 220 | goto err; |
155 | } | 221 | } |
156 | 222 | ||
@@ -160,63 +226,29 @@ next_desc: | |||
160 | usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); | 226 | usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); |
161 | } | 227 | } |
162 | 228 | ||
163 | /* success! point the user to the management interface */ | 229 | /* claim data interface and set it up */ |
164 | if (control) | 230 | status = usb_driver_claim_interface(driver, info->data, dev); |
165 | dev_info(&intf->dev, "Use \"" DM_DRIVER "\" for QMI interface %s\n", | 231 | if (status < 0) |
166 | dev_name(&control->dev)); | 232 | goto err; |
167 | |||
168 | /* XXX: add a sysfs symlink somewhere to help management applications find it? */ | ||
169 | 233 | ||
170 | /* collect bulk endpoints now that we know intf == "data" interface */ | 234 | status = qmi_wwan_register_subdriver(dev); |
171 | status = usbnet_get_endpoints(dev, intf); | 235 | if (status < 0) { |
236 | usb_set_intfdata(info->data, NULL); | ||
237 | usb_driver_release_interface(driver, info->data); | ||
238 | } | ||
172 | 239 | ||
173 | err: | 240 | err: |
174 | return status; | 241 | return status; |
175 | } | 242 | } |
176 | 243 | ||
177 | /* using a counter to merge subdriver requests with our own into a combined state */ | ||
178 | static int qmi_wwan_manage_power(struct usbnet *dev, int on) | ||
179 | { | ||
180 | atomic_t *pmcount = (void *)&dev->data[1]; | ||
181 | int rv = 0; | ||
182 | |||
183 | dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on); | ||
184 | |||
185 | if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) { | ||
186 | /* need autopm_get/put here to ensure the usbcore sees the new value */ | ||
187 | rv = usb_autopm_get_interface(dev->intf); | ||
188 | if (rv < 0) | ||
189 | goto err; | ||
190 | dev->intf->needs_remote_wakeup = on; | ||
191 | usb_autopm_put_interface(dev->intf); | ||
192 | } | ||
193 | err: | ||
194 | return rv; | ||
195 | } | ||
196 | |||
197 | static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) | ||
198 | { | ||
199 | struct usbnet *dev = usb_get_intfdata(intf); | ||
200 | |||
201 | /* can be called while disconnecting */ | ||
202 | if (!dev) | ||
203 | return 0; | ||
204 | return qmi_wwan_manage_power(dev, on); | ||
205 | } | ||
206 | |||
207 | /* Some devices combine the "control" and "data" functions into a | 244 | /* Some devices combine the "control" and "data" functions into a |
208 | * single interface with all three endpoints: interrupt + bulk in and | 245 | * single interface with all three endpoints: interrupt + bulk in and |
209 | * out | 246 | * out |
210 | * | 247 | */ |
211 | * Setting up cdc-wdm as a subdriver owning the interrupt endpoint | ||
212 | * will let it provide userspace access to the encapsulated QMI | ||
213 | * protocol without interfering with the usbnet operations. | ||
214 | */ | ||
215 | static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) | 248 | static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) |
216 | { | 249 | { |
217 | int rv; | 250 | int rv; |
218 | struct usb_driver *subdriver = NULL; | 251 | struct qmi_wwan_state *info = (void *)&dev->data; |
219 | atomic_t *pmcount = (void *)&dev->data[1]; | ||
220 | 252 | ||
221 | /* ZTE makes devices where the interface descriptors and endpoint | 253 | /* ZTE makes devices where the interface descriptors and endpoint |
222 | * configurations of two or more interfaces are identical, even | 254 | * configurations of two or more interfaces are identical, even |
@@ -232,43 +264,39 @@ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) | |||
232 | goto err; | 264 | goto err; |
233 | } | 265 | } |
234 | 266 | ||
235 | atomic_set(pmcount, 0); | 267 | /* control and data is shared */ |
236 | 268 | info->control = intf; | |
237 | /* collect all three endpoints */ | 269 | info->data = intf; |
238 | rv = usbnet_get_endpoints(dev, intf); | 270 | rv = qmi_wwan_register_subdriver(dev); |
239 | if (rv < 0) | ||
240 | goto err; | ||
241 | |||
242 | /* require interrupt endpoint for subdriver */ | ||
243 | if (!dev->status) { | ||
244 | rv = -EINVAL; | ||
245 | goto err; | ||
246 | } | ||
247 | |||
248 | subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); | ||
249 | if (IS_ERR(subdriver)) { | ||
250 | rv = PTR_ERR(subdriver); | ||
251 | goto err; | ||
252 | } | ||
253 | |||
254 | /* can't let usbnet use the interrupt endpoint */ | ||
255 | dev->status = NULL; | ||
256 | |||
257 | /* save subdriver struct for suspend/resume wrappers */ | ||
258 | dev->data[0] = (unsigned long)subdriver; | ||
259 | 271 | ||
260 | err: | 272 | err: |
261 | return rv; | 273 | return rv; |
262 | } | 274 | } |
263 | 275 | ||
264 | static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf) | 276 | static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) |
265 | { | 277 | { |
266 | struct usb_driver *subdriver = (void *)dev->data[0]; | 278 | struct qmi_wwan_state *info = (void *)&dev->data; |
267 | 279 | struct usb_driver *driver = driver_of(intf); | |
268 | if (subdriver && subdriver->disconnect) | 280 | struct usb_interface *other; |
269 | subdriver->disconnect(intf); | 281 | |
282 | if (info->subdriver && info->subdriver->disconnect) | ||
283 | info->subdriver->disconnect(info->control); | ||
284 | |||
285 | /* allow user to unbind using either control or data */ | ||
286 | if (intf == info->control) | ||
287 | other = info->data; | ||
288 | else | ||
289 | other = info->control; | ||
290 | |||
291 | /* only if not shared */ | ||
292 | if (other && intf != other) { | ||
293 | usb_set_intfdata(other, NULL); | ||
294 | usb_driver_release_interface(driver, other); | ||
295 | } | ||
270 | 296 | ||
271 | dev->data[0] = (unsigned long)NULL; | 297 | info->subdriver = NULL; |
298 | info->data = NULL; | ||
299 | info->control = NULL; | ||
272 | } | 300 | } |
273 | 301 | ||
274 | /* suspend/resume wrappers calling both usbnet and the cdc-wdm | 302 | /* suspend/resume wrappers calling both usbnet and the cdc-wdm |
@@ -280,15 +308,15 @@ static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *int | |||
280 | static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) | 308 | static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) |
281 | { | 309 | { |
282 | struct usbnet *dev = usb_get_intfdata(intf); | 310 | struct usbnet *dev = usb_get_intfdata(intf); |
283 | struct usb_driver *subdriver = (void *)dev->data[0]; | 311 | struct qmi_wwan_state *info = (void *)&dev->data; |
284 | int ret; | 312 | int ret; |
285 | 313 | ||
286 | ret = usbnet_suspend(intf, message); | 314 | ret = usbnet_suspend(intf, message); |
287 | if (ret < 0) | 315 | if (ret < 0) |
288 | goto err; | 316 | goto err; |
289 | 317 | ||
290 | if (subdriver && subdriver->suspend) | 318 | if (info->subdriver && info->subdriver->suspend) |
291 | ret = subdriver->suspend(intf, message); | 319 | ret = info->subdriver->suspend(intf, message); |
292 | if (ret < 0) | 320 | if (ret < 0) |
293 | usbnet_resume(intf); | 321 | usbnet_resume(intf); |
294 | err: | 322 | err: |
@@ -298,33 +326,33 @@ err: | |||
298 | static int qmi_wwan_resume(struct usb_interface *intf) | 326 | static int qmi_wwan_resume(struct usb_interface *intf) |
299 | { | 327 | { |
300 | struct usbnet *dev = usb_get_intfdata(intf); | 328 | struct usbnet *dev = usb_get_intfdata(intf); |
301 | struct usb_driver *subdriver = (void *)dev->data[0]; | 329 | struct qmi_wwan_state *info = (void *)&dev->data; |
302 | int ret = 0; | 330 | int ret = 0; |
303 | 331 | ||
304 | if (subdriver && subdriver->resume) | 332 | if (info->subdriver && info->subdriver->resume) |
305 | ret = subdriver->resume(intf); | 333 | ret = info->subdriver->resume(intf); |
306 | if (ret < 0) | 334 | if (ret < 0) |
307 | goto err; | 335 | goto err; |
308 | ret = usbnet_resume(intf); | 336 | ret = usbnet_resume(intf); |
309 | if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend) | 337 | if (ret < 0 && info->subdriver && info->subdriver->resume && info->subdriver->suspend) |
310 | subdriver->suspend(intf, PMSG_SUSPEND); | 338 | info->subdriver->suspend(intf, PMSG_SUSPEND); |
311 | err: | 339 | err: |
312 | return ret; | 340 | return ret; |
313 | } | 341 | } |
314 | 342 | ||
315 | |||
316 | static const struct driver_info qmi_wwan_info = { | 343 | static const struct driver_info qmi_wwan_info = { |
317 | .description = "QMI speaking wwan device", | 344 | .description = "WWAN/QMI device", |
318 | .flags = FLAG_WWAN, | 345 | .flags = FLAG_WWAN, |
319 | .bind = qmi_wwan_bind, | 346 | .bind = qmi_wwan_bind, |
347 | .unbind = qmi_wwan_unbind, | ||
320 | .manage_power = qmi_wwan_manage_power, | 348 | .manage_power = qmi_wwan_manage_power, |
321 | }; | 349 | }; |
322 | 350 | ||
323 | static const struct driver_info qmi_wwan_shared = { | 351 | static const struct driver_info qmi_wwan_shared = { |
324 | .description = "QMI speaking wwan device with combined interface", | 352 | .description = "WWAN/QMI device", |
325 | .flags = FLAG_WWAN, | 353 | .flags = FLAG_WWAN, |
326 | .bind = qmi_wwan_bind_shared, | 354 | .bind = qmi_wwan_bind_shared, |
327 | .unbind = qmi_wwan_unbind_shared, | 355 | .unbind = qmi_wwan_unbind, |
328 | .manage_power = qmi_wwan_manage_power, | 356 | .manage_power = qmi_wwan_manage_power, |
329 | }; | 357 | }; |
330 | 358 | ||
@@ -332,7 +360,7 @@ static const struct driver_info qmi_wwan_force_int0 = { | |||
332 | .description = "Qualcomm WWAN/QMI device", | 360 | .description = "Qualcomm WWAN/QMI device", |
333 | .flags = FLAG_WWAN, | 361 | .flags = FLAG_WWAN, |
334 | .bind = qmi_wwan_bind_shared, | 362 | .bind = qmi_wwan_bind_shared, |
335 | .unbind = qmi_wwan_unbind_shared, | 363 | .unbind = qmi_wwan_unbind, |
336 | .manage_power = qmi_wwan_manage_power, | 364 | .manage_power = qmi_wwan_manage_power, |
337 | .data = BIT(0), /* interface whitelist bitmap */ | 365 | .data = BIT(0), /* interface whitelist bitmap */ |
338 | }; | 366 | }; |
@@ -341,16 +369,25 @@ static const struct driver_info qmi_wwan_force_int1 = { | |||
341 | .description = "Qualcomm WWAN/QMI device", | 369 | .description = "Qualcomm WWAN/QMI device", |
342 | .flags = FLAG_WWAN, | 370 | .flags = FLAG_WWAN, |
343 | .bind = qmi_wwan_bind_shared, | 371 | .bind = qmi_wwan_bind_shared, |
344 | .unbind = qmi_wwan_unbind_shared, | 372 | .unbind = qmi_wwan_unbind, |
345 | .manage_power = qmi_wwan_manage_power, | 373 | .manage_power = qmi_wwan_manage_power, |
346 | .data = BIT(1), /* interface whitelist bitmap */ | 374 | .data = BIT(1), /* interface whitelist bitmap */ |
347 | }; | 375 | }; |
348 | 376 | ||
377 | static const struct driver_info qmi_wwan_force_int2 = { | ||
378 | .description = "Qualcomm WWAN/QMI device", | ||
379 | .flags = FLAG_WWAN, | ||
380 | .bind = qmi_wwan_bind_shared, | ||
381 | .unbind = qmi_wwan_unbind, | ||
382 | .manage_power = qmi_wwan_manage_power, | ||
383 | .data = BIT(2), /* interface whitelist bitmap */ | ||
384 | }; | ||
385 | |||
349 | static const struct driver_info qmi_wwan_force_int3 = { | 386 | static const struct driver_info qmi_wwan_force_int3 = { |
350 | .description = "Qualcomm WWAN/QMI device", | 387 | .description = "Qualcomm WWAN/QMI device", |
351 | .flags = FLAG_WWAN, | 388 | .flags = FLAG_WWAN, |
352 | .bind = qmi_wwan_bind_shared, | 389 | .bind = qmi_wwan_bind_shared, |
353 | .unbind = qmi_wwan_unbind_shared, | 390 | .unbind = qmi_wwan_unbind, |
354 | .manage_power = qmi_wwan_manage_power, | 391 | .manage_power = qmi_wwan_manage_power, |
355 | .data = BIT(3), /* interface whitelist bitmap */ | 392 | .data = BIT(3), /* interface whitelist bitmap */ |
356 | }; | 393 | }; |
@@ -359,7 +396,7 @@ static const struct driver_info qmi_wwan_force_int4 = { | |||
359 | .description = "Qualcomm WWAN/QMI device", | 396 | .description = "Qualcomm WWAN/QMI device", |
360 | .flags = FLAG_WWAN, | 397 | .flags = FLAG_WWAN, |
361 | .bind = qmi_wwan_bind_shared, | 398 | .bind = qmi_wwan_bind_shared, |
362 | .unbind = qmi_wwan_unbind_shared, | 399 | .unbind = qmi_wwan_unbind, |
363 | .manage_power = qmi_wwan_manage_power, | 400 | .manage_power = qmi_wwan_manage_power, |
364 | .data = BIT(4), /* interface whitelist bitmap */ | 401 | .data = BIT(4), /* interface whitelist bitmap */ |
365 | }; | 402 | }; |
@@ -381,7 +418,7 @@ static const struct driver_info qmi_wwan_sierra = { | |||
381 | .description = "Sierra Wireless wwan/QMI device", | 418 | .description = "Sierra Wireless wwan/QMI device", |
382 | .flags = FLAG_WWAN, | 419 | .flags = FLAG_WWAN, |
383 | .bind = qmi_wwan_bind_shared, | 420 | .bind = qmi_wwan_bind_shared, |
384 | .unbind = qmi_wwan_unbind_shared, | 421 | .unbind = qmi_wwan_unbind, |
385 | .manage_power = qmi_wwan_manage_power, | 422 | .manage_power = qmi_wwan_manage_power, |
386 | .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ | 423 | .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ |
387 | }; | 424 | }; |
@@ -404,7 +441,7 @@ static const struct usb_device_id products[] = { | |||
404 | .idVendor = HUAWEI_VENDOR_ID, | 441 | .idVendor = HUAWEI_VENDOR_ID, |
405 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 442 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
406 | .bInterfaceSubClass = 1, | 443 | .bInterfaceSubClass = 1, |
407 | .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ | 444 | .bInterfaceProtocol = 9, /* CDC Ethernet *control* interface */ |
408 | .driver_info = (unsigned long)&qmi_wwan_info, | 445 | .driver_info = (unsigned long)&qmi_wwan_info, |
409 | }, | 446 | }, |
410 | { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ | 447 | { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ |
@@ -412,7 +449,7 @@ static const struct usb_device_id products[] = { | |||
412 | .idVendor = HUAWEI_VENDOR_ID, | 449 | .idVendor = HUAWEI_VENDOR_ID, |
413 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 450 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
414 | .bInterfaceSubClass = 1, | 451 | .bInterfaceSubClass = 1, |
415 | .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */ | 452 | .bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */ |
416 | .driver_info = (unsigned long)&qmi_wwan_info, | 453 | .driver_info = (unsigned long)&qmi_wwan_info, |
417 | }, | 454 | }, |
418 | { /* Huawei E392, E398 and possibly others in "Windows mode" | 455 | { /* Huawei E392, E398 and possibly others in "Windows mode" |
@@ -444,6 +481,15 @@ static const struct usb_device_id products[] = { | |||
444 | .bInterfaceProtocol = 0xff, | 481 | .bInterfaceProtocol = 0xff, |
445 | .driver_info = (unsigned long)&qmi_wwan_force_int4, | 482 | .driver_info = (unsigned long)&qmi_wwan_force_int4, |
446 | }, | 483 | }, |
484 | { /* ZTE MF821D */ | ||
485 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, | ||
486 | .idVendor = 0x19d2, | ||
487 | .idProduct = 0x0326, | ||
488 | .bInterfaceClass = 0xff, | ||
489 | .bInterfaceSubClass = 0xff, | ||
490 | .bInterfaceProtocol = 0xff, | ||
491 | .driver_info = (unsigned long)&qmi_wwan_force_int4, | ||
492 | }, | ||
447 | { /* ZTE (Vodafone) K3520-Z */ | 493 | { /* ZTE (Vodafone) K3520-Z */ |
448 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, | 494 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, |
449 | .idVendor = 0x19d2, | 495 | .idVendor = 0x19d2, |
@@ -498,6 +544,15 @@ static const struct usb_device_id products[] = { | |||
498 | .bInterfaceProtocol = 0xff, | 544 | .bInterfaceProtocol = 0xff, |
499 | .driver_info = (unsigned long)&qmi_wwan_force_int4, | 545 | .driver_info = (unsigned long)&qmi_wwan_force_int4, |
500 | }, | 546 | }, |
547 | { /* ZTE MF60 */ | ||
548 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, | ||
549 | .idVendor = 0x19d2, | ||
550 | .idProduct = 0x1402, | ||
551 | .bInterfaceClass = 0xff, | ||
552 | .bInterfaceSubClass = 0xff, | ||
553 | .bInterfaceProtocol = 0xff, | ||
554 | .driver_info = (unsigned long)&qmi_wwan_force_int2, | ||
555 | }, | ||
501 | { /* Sierra Wireless MC77xx in QMI mode */ | 556 | { /* Sierra Wireless MC77xx in QMI mode */ |
502 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, | 557 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, |
503 | .idVendor = 0x1199, | 558 | .idVendor = 0x1199, |
@@ -554,10 +609,27 @@ static const struct usb_device_id products[] = { | |||
554 | }; | 609 | }; |
555 | MODULE_DEVICE_TABLE(usb, products); | 610 | MODULE_DEVICE_TABLE(usb, products); |
556 | 611 | ||
612 | static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id *prod) | ||
613 | { | ||
614 | struct usb_device_id *id = (struct usb_device_id *)prod; | ||
615 | |||
616 | /* Workaround to enable dynamic IDs. This disables usbnet | ||
617 | * blacklisting functionality. Which, if required, can be | ||
618 | * reimplemented here by using a magic "blacklist" value | ||
619 | * instead of 0 in the static device id table | ||
620 | */ | ||
621 | if (!id->driver_info) { | ||
622 | dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); | ||
623 | id->driver_info = (unsigned long)&qmi_wwan_shared; | ||
624 | } | ||
625 | |||
626 | return usbnet_probe(intf, id); | ||
627 | } | ||
628 | |||
557 | static struct usb_driver qmi_wwan_driver = { | 629 | static struct usb_driver qmi_wwan_driver = { |
558 | .name = "qmi_wwan", | 630 | .name = "qmi_wwan", |
559 | .id_table = products, | 631 | .id_table = products, |
560 | .probe = usbnet_probe, | 632 | .probe = qmi_wwan_probe, |
561 | .disconnect = usbnet_disconnect, | 633 | .disconnect = usbnet_disconnect, |
562 | .suspend = qmi_wwan_suspend, | 634 | .suspend = qmi_wwan_suspend, |
563 | .resume = qmi_wwan_resume, | 635 | .resume = qmi_wwan_resume, |
@@ -566,17 +638,7 @@ static struct usb_driver qmi_wwan_driver = { | |||
566 | .disable_hub_initiated_lpm = 1, | 638 | .disable_hub_initiated_lpm = 1, |
567 | }; | 639 | }; |
568 | 640 | ||
569 | static int __init qmi_wwan_init(void) | 641 | module_usb_driver(qmi_wwan_driver); |
570 | { | ||
571 | return usb_register(&qmi_wwan_driver); | ||
572 | } | ||
573 | module_init(qmi_wwan_init); | ||
574 | |||
575 | static void __exit qmi_wwan_exit(void) | ||
576 | { | ||
577 | usb_deregister(&qmi_wwan_driver); | ||
578 | } | ||
579 | module_exit(qmi_wwan_exit); | ||
580 | 642 | ||
581 | MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>"); | 643 | MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>"); |
582 | MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); | 644 | MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); |
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 1c6e51588da7..f5ab6e613ec8 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c | |||
@@ -616,7 +616,7 @@ static void smsc75xx_init_mac_address(struct usbnet *dev) | |||
616 | 616 | ||
617 | /* no eeprom, or eeprom values are invalid. generate random MAC */ | 617 | /* no eeprom, or eeprom values are invalid. generate random MAC */ |
618 | eth_hw_addr_random(dev->net); | 618 | eth_hw_addr_random(dev->net); |
619 | netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr"); | 619 | netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr"); |
620 | } | 620 | } |
621 | 621 | ||
622 | static int smsc75xx_set_mac_address(struct usbnet *dev) | 622 | static int smsc75xx_set_mac_address(struct usbnet *dev) |
@@ -1260,6 +1260,6 @@ static struct usb_driver smsc75xx_driver = { | |||
1260 | module_usb_driver(smsc75xx_driver); | 1260 | module_usb_driver(smsc75xx_driver); |
1261 | 1261 | ||
1262 | MODULE_AUTHOR("Nancy Lin"); | 1262 | MODULE_AUTHOR("Nancy Lin"); |
1263 | MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); | 1263 | MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>"); |
1264 | MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); | 1264 | MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); |
1265 | MODULE_LICENSE("GPL"); | 1265 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index b1112e753859..d45e539a84b7 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -578,6 +578,36 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, | |||
578 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); | 578 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); |
579 | } | 579 | } |
580 | 580 | ||
581 | static int smsc95xx_ethtool_getregslen(struct net_device *netdev) | ||
582 | { | ||
583 | /* all smsc95xx registers */ | ||
584 | return COE_CR - ID_REV + 1; | ||
585 | } | ||
586 | |||
587 | static void | ||
588 | smsc95xx_ethtool_getregs(struct net_device *netdev, struct ethtool_regs *regs, | ||
589 | void *buf) | ||
590 | { | ||
591 | struct usbnet *dev = netdev_priv(netdev); | ||
592 | unsigned int i, j; | ||
593 | int retval; | ||
594 | u32 *data = buf; | ||
595 | |||
596 | retval = smsc95xx_read_reg(dev, ID_REV, ®s->version); | ||
597 | if (retval < 0) { | ||
598 | netdev_warn(netdev, "REGS: cannot read ID_REV\n"); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | for (i = ID_REV, j = 0; i <= COE_CR; i += (sizeof(u32)), j++) { | ||
603 | retval = smsc95xx_read_reg(dev, i, &data[j]); | ||
604 | if (retval < 0) { | ||
605 | netdev_warn(netdev, "REGS: cannot read reg[%x]\n", i); | ||
606 | return; | ||
607 | } | ||
608 | } | ||
609 | } | ||
610 | |||
581 | static const struct ethtool_ops smsc95xx_ethtool_ops = { | 611 | static const struct ethtool_ops smsc95xx_ethtool_ops = { |
582 | .get_link = usbnet_get_link, | 612 | .get_link = usbnet_get_link, |
583 | .nway_reset = usbnet_nway_reset, | 613 | .nway_reset = usbnet_nway_reset, |
@@ -589,6 +619,8 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { | |||
589 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, | 619 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, |
590 | .get_eeprom = smsc95xx_ethtool_get_eeprom, | 620 | .get_eeprom = smsc95xx_ethtool_get_eeprom, |
591 | .set_eeprom = smsc95xx_ethtool_set_eeprom, | 621 | .set_eeprom = smsc95xx_ethtool_set_eeprom, |
622 | .get_regs_len = smsc95xx_ethtool_getregslen, | ||
623 | .get_regs = smsc95xx_ethtool_getregs, | ||
592 | }; | 624 | }; |
593 | 625 | ||
594 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 626 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -615,7 +647,7 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) | |||
615 | 647 | ||
616 | /* no eeprom, or eeprom values are invalid. generate random MAC */ | 648 | /* no eeprom, or eeprom values are invalid. generate random MAC */ |
617 | eth_hw_addr_random(dev->net); | 649 | eth_hw_addr_random(dev->net); |
618 | netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n"); | 650 | netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); |
619 | } | 651 | } |
620 | 652 | ||
621 | static int smsc95xx_set_mac_address(struct usbnet *dev) | 653 | static int smsc95xx_set_mac_address(struct usbnet *dev) |
@@ -1303,6 +1335,6 @@ static struct usb_driver smsc95xx_driver = { | |||
1303 | module_usb_driver(smsc95xx_driver); | 1335 | module_usb_driver(smsc95xx_driver); |
1304 | 1336 | ||
1305 | MODULE_AUTHOR("Nancy Lin"); | 1337 | MODULE_AUTHOR("Nancy Lin"); |
1306 | MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); | 1338 | MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>"); |
1307 | MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices"); | 1339 | MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices"); |
1308 | MODULE_LICENSE("GPL"); | 1340 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index aba769d77459..8531c1caac28 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -180,7 +180,40 @@ int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress) | |||
180 | } | 180 | } |
181 | EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); | 181 | EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr); |
182 | 182 | ||
183 | static void intr_complete (struct urb *urb); | 183 | static void intr_complete (struct urb *urb) |
184 | { | ||
185 | struct usbnet *dev = urb->context; | ||
186 | int status = urb->status; | ||
187 | |||
188 | switch (status) { | ||
189 | /* success */ | ||
190 | case 0: | ||
191 | dev->driver_info->status(dev, urb); | ||
192 | break; | ||
193 | |||
194 | /* software-driven interface shutdown */ | ||
195 | case -ENOENT: /* urb killed */ | ||
196 | case -ESHUTDOWN: /* hardware gone */ | ||
197 | netif_dbg(dev, ifdown, dev->net, | ||
198 | "intr shutdown, code %d\n", status); | ||
199 | return; | ||
200 | |||
201 | /* NOTE: not throttling like RX/TX, since this endpoint | ||
202 | * already polls infrequently | ||
203 | */ | ||
204 | default: | ||
205 | netdev_dbg(dev->net, "intr status %d\n", status); | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | if (!netif_running (dev->net)) | ||
210 | return; | ||
211 | |||
212 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
213 | if (status != 0) | ||
214 | netif_err(dev, timer, dev->net, | ||
215 | "intr resubmit --> %d\n", status); | ||
216 | } | ||
184 | 217 | ||
185 | static int init_status (struct usbnet *dev, struct usb_interface *intf) | 218 | static int init_status (struct usbnet *dev, struct usb_interface *intf) |
186 | { | 219 | { |
@@ -519,42 +552,6 @@ block: | |||
519 | netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); | 552 | netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); |
520 | } | 553 | } |
521 | 554 | ||
522 | static void intr_complete (struct urb *urb) | ||
523 | { | ||
524 | struct usbnet *dev = urb->context; | ||
525 | int status = urb->status; | ||
526 | |||
527 | switch (status) { | ||
528 | /* success */ | ||
529 | case 0: | ||
530 | dev->driver_info->status(dev, urb); | ||
531 | break; | ||
532 | |||
533 | /* software-driven interface shutdown */ | ||
534 | case -ENOENT: /* urb killed */ | ||
535 | case -ESHUTDOWN: /* hardware gone */ | ||
536 | netif_dbg(dev, ifdown, dev->net, | ||
537 | "intr shutdown, code %d\n", status); | ||
538 | return; | ||
539 | |||
540 | /* NOTE: not throttling like RX/TX, since this endpoint | ||
541 | * already polls infrequently | ||
542 | */ | ||
543 | default: | ||
544 | netdev_dbg(dev->net, "intr status %d\n", status); | ||
545 | break; | ||
546 | } | ||
547 | |||
548 | if (!netif_running (dev->net)) | ||
549 | return; | ||
550 | |||
551 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); | ||
552 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
553 | if (status != 0) | ||
554 | netif_err(dev, timer, dev->net, | ||
555 | "intr resubmit --> %d\n", status); | ||
556 | } | ||
557 | |||
558 | /*-------------------------------------------------------------------------*/ | 555 | /*-------------------------------------------------------------------------*/ |
559 | void usbnet_pause_rx(struct usbnet *dev) | 556 | void usbnet_pause_rx(struct usbnet *dev) |
560 | { | 557 | { |
@@ -1312,7 +1309,6 @@ void usbnet_disconnect (struct usb_interface *intf) | |||
1312 | usb_free_urb(dev->interrupt); | 1309 | usb_free_urb(dev->interrupt); |
1313 | 1310 | ||
1314 | free_netdev(net); | 1311 | free_netdev(net); |
1315 | usb_put_dev (xdev); | ||
1316 | } | 1312 | } |
1317 | EXPORT_SYMBOL_GPL(usbnet_disconnect); | 1313 | EXPORT_SYMBOL_GPL(usbnet_disconnect); |
1318 | 1314 | ||
@@ -1368,8 +1364,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1368 | xdev = interface_to_usbdev (udev); | 1364 | xdev = interface_to_usbdev (udev); |
1369 | interface = udev->cur_altsetting; | 1365 | interface = udev->cur_altsetting; |
1370 | 1366 | ||
1371 | usb_get_dev (xdev); | ||
1372 | |||
1373 | status = -ENOMEM; | 1367 | status = -ENOMEM; |
1374 | 1368 | ||
1375 | // set up our own records | 1369 | // set up our own records |
@@ -1498,7 +1492,6 @@ out3: | |||
1498 | out1: | 1492 | out1: |
1499 | free_netdev(net); | 1493 | free_netdev(net); |
1500 | out: | 1494 | out: |
1501 | usb_put_dev(xdev); | ||
1502 | return status; | 1495 | return status; |
1503 | } | 1496 | } |
1504 | EXPORT_SYMBOL_GPL(usbnet_probe); | 1497 | EXPORT_SYMBOL_GPL(usbnet_probe); |
@@ -1600,7 +1593,7 @@ static int __init usbnet_init(void) | |||
1600 | BUILD_BUG_ON( | 1593 | BUILD_BUG_ON( |
1601 | FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); | 1594 | FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); |
1602 | 1595 | ||
1603 | random_ether_addr(node_id); | 1596 | eth_random_addr(node_id); |
1604 | return 0; | 1597 | return 0; |
1605 | } | 1598 | } |
1606 | module_init(usbnet_init); | 1599 | module_init(usbnet_init); |