aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhayeswang <hayeswang@realtek.com>2014-03-04 07:47:48 -0500
committerDavid S. Miller <davem@davemloft.net>2014-03-05 20:40:24 -0500
commit10c3271712f58215f4d336a1e30aa25be09cd5d1 (patch)
tree3a370fa20e3939a24d3ae62a537dec6dc105fee3
parent367d56f7b4d5ce61e883c64f81786c7a3ae88eea (diff)
r8152: disable the ECM mode
There are known issues for switching the drivers between ECM mode and vendor mode. The interrup transfer may become abnormal. The hardware may have the opportunity to die if you change the configuration without unloading the current driver first, because all the control transfers of the current driver would fail after the command of switching the configuration. Although to use the ecm driver and vendor driver independently is fine, it may have problems to change the driver from one to the other by switching the configuration. Additionally, now the vendor mode driver is more powerful than the ECM driver. Thus, disable the ECM mode driver, and let r8152 to set the configuration to vendor mode and reset the device automatically. Signed-off-by: Hayes Wang <hayeswang@realtek.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/Makefile2
-rw-r--r--drivers/net/usb/cdc_ether.c7
-rw-r--r--drivers/net/usb/r8152.c15
-rw-r--r--drivers/net/usb/r815x.c248
4 files changed, 17 insertions, 255 deletions
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 433f0a00c683..e2797f1e1b31 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_USB_HSO) += hso.o
11obj-$(CONFIG_USB_NET_AX8817X) += asix.o 11obj-$(CONFIG_USB_NET_AX8817X) += asix.o
12asix-y := asix_devices.o asix_common.o ax88172a.o 12asix-y := asix_devices.o asix_common.o ax88172a.o
13obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o 13obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o
14obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o 14obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
15obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o 15obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
16obj-$(CONFIG_USB_NET_DM9601) += dm9601.o 16obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
17obj-$(CONFIG_USB_NET_SR9700) += sr9700.o 17obj-$(CONFIG_USB_NET_SR9700) += sr9700.o
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 42e176912c8e..bd363b27e854 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -652,6 +652,13 @@ static const struct usb_device_id products[] = {
652 .driver_info = 0, 652 .driver_info = 0,
653}, 653},
654 654
655/* Samsung USB Ethernet Adapters */
656{
657 USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
658 USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
659 .driver_info = 0,
660},
661
655/* WHITELIST!!! 662/* WHITELIST!!!
656 * 663 *
657 * CDC Ether uses two interfaces, not necessarily consecutive. 664 * CDC Ether uses two interfaces, not necessarily consecutive.
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d89dbe395ad2..adb12f349a61 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -449,9 +449,6 @@ enum rtl8152_flags {
449#define MCU_TYPE_PLA 0x0100 449#define MCU_TYPE_PLA 0x0100
450#define MCU_TYPE_USB 0x0000 450#define MCU_TYPE_USB 0x0000
451 451
452#define REALTEK_USB_DEVICE(vend, prod) \
453 USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
454
455struct rx_desc { 452struct rx_desc {
456 __le32 opts1; 453 __le32 opts1;
457#define RX_LEN_MASK 0x7fff 454#define RX_LEN_MASK 0x7fff
@@ -2739,6 +2736,12 @@ static int rtl8152_probe(struct usb_interface *intf,
2739 struct net_device *netdev; 2736 struct net_device *netdev;
2740 int ret; 2737 int ret;
2741 2738
2739 if (udev->actconfig->desc.bConfigurationValue != 1) {
2740 usb_driver_set_configuration(udev, 1);
2741 return -ENODEV;
2742 }
2743
2744 usb_reset_device(udev);
2742 netdev = alloc_etherdev(sizeof(struct r8152)); 2745 netdev = alloc_etherdev(sizeof(struct r8152));
2743 if (!netdev) { 2746 if (!netdev) {
2744 dev_err(&intf->dev, "Out of memory\n"); 2747 dev_err(&intf->dev, "Out of memory\n");
@@ -2819,9 +2822,9 @@ static void rtl8152_disconnect(struct usb_interface *intf)
2819 2822
2820/* table of devices that work with this driver */ 2823/* table of devices that work with this driver */
2821static struct usb_device_id rtl8152_table[] = { 2824static struct usb_device_id rtl8152_table[] = {
2822 {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, 2825 {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
2823 {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, 2826 {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
2824 {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, 2827 {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
2825 {} 2828 {}
2826}; 2829};
2827 2830
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644
index f0a8791b7636..000000000000
--- a/drivers/net/usb/r815x.c
+++ /dev/null
@@ -1,248 +0,0 @@
1#include <linux/module.h>
2#include <linux/netdevice.h>
3#include <linux/mii.h>
4#include <linux/usb.h>
5#include <linux/usb/cdc.h>
6#include <linux/usb/usbnet.h>
7
8#define RTL815x_REQT_READ 0xc0
9#define RTL815x_REQT_WRITE 0x40
10#define RTL815x_REQ_GET_REGS 0x05
11#define RTL815x_REQ_SET_REGS 0x05
12
13#define MCU_TYPE_PLA 0x0100
14#define OCP_BASE 0xe86c
15#define BASE_MII 0xa400
16
17#define BYTE_EN_DWORD 0xff
18#define BYTE_EN_WORD 0x33
19#define BYTE_EN_BYTE 0x11
20
21#define R815x_PHY_ID 32
22#define REALTEK_VENDOR_ID 0x0bda
23
24
25static int pla_read_word(struct usb_device *udev, u16 index)
26{
27 int ret;
28 u8 shift = index & 2;
29 __le32 *tmp;
30
31 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
32 if (!tmp)
33 return -ENOMEM;
34
35 index &= ~3;
36
37 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
38 RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
39 index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
40 if (ret < 0)
41 goto out2;
42
43 ret = __le32_to_cpu(*tmp);
44 ret >>= (shift * 8);
45 ret &= 0xffff;
46
47out2:
48 kfree(tmp);
49 return ret;
50}
51
52static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
53{
54 __le32 *tmp;
55 u32 mask = 0xffff;
56 u16 byen = BYTE_EN_WORD;
57 u8 shift = index & 2;
58 int ret;
59
60 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
61 if (!tmp)
62 return -ENOMEM;
63
64 data &= mask;
65
66 if (shift) {
67 byen <<= shift;
68 mask <<= (shift * 8);
69 data <<= (shift * 8);
70 index &= ~3;
71 }
72
73 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
74 RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
75 index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
76 if (ret < 0)
77 goto out3;
78
79 data |= __le32_to_cpu(*tmp) & ~mask;
80 *tmp = __cpu_to_le32(data);
81
82 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
83 RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
84 index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
85 500);
86
87out3:
88 kfree(tmp);
89 return ret;
90}
91
92static int ocp_reg_read(struct usbnet *dev, u16 addr)
93{
94 u16 ocp_base, ocp_index;
95 int ret;
96
97 ocp_base = addr & 0xf000;
98 ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
99 if (ret < 0)
100 goto out;
101
102 ocp_index = (addr & 0x0fff) | 0xb000;
103 ret = pla_read_word(dev->udev, ocp_index);
104
105out:
106 return ret;
107}
108
109static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
110{
111 u16 ocp_base, ocp_index;
112 int ret;
113
114 ocp_base = addr & 0xf000;
115 ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
116 if (ret < 0)
117 goto out1;
118
119 ocp_index = (addr & 0x0fff) | 0xb000;
120 ret = pla_write_word(dev->udev, ocp_index, data);
121
122out1:
123 return ret;
124}
125
126static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
127{
128 struct usbnet *dev = netdev_priv(netdev);
129 int ret;
130
131 if (phy_id != R815x_PHY_ID)
132 return -EINVAL;
133
134 if (usb_autopm_get_interface(dev->intf) < 0)
135 return -ENODEV;
136
137 ret = ocp_reg_read(dev, BASE_MII + reg * 2);
138
139 usb_autopm_put_interface(dev->intf);
140 return ret;
141}
142
143static
144void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
145{
146 struct usbnet *dev = netdev_priv(netdev);
147
148 if (phy_id != R815x_PHY_ID)
149 return;
150
151 if (usb_autopm_get_interface(dev->intf) < 0)
152 return;
153
154 ocp_reg_write(dev, BASE_MII + reg * 2, val);
155
156 usb_autopm_put_interface(dev->intf);
157}
158
159static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
160{
161 int status;
162
163 status = usbnet_cdc_bind(dev, intf);
164 if (status < 0)
165 return status;
166
167 dev->mii.dev = dev->net;
168 dev->mii.mdio_read = r815x_mdio_read;
169 dev->mii.mdio_write = r815x_mdio_write;
170 dev->mii.phy_id_mask = 0x3f;
171 dev->mii.reg_num_mask = 0x1f;
172 dev->mii.phy_id = R815x_PHY_ID;
173 dev->mii.supports_gmii = 1;
174
175 return status;
176}
177
178static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
179{
180 int status;
181
182 status = usbnet_cdc_bind(dev, intf);
183 if (status < 0)
184 return status;
185
186 dev->mii.dev = dev->net;
187 dev->mii.mdio_read = r815x_mdio_read;
188 dev->mii.mdio_write = r815x_mdio_write;
189 dev->mii.phy_id_mask = 0x3f;
190 dev->mii.reg_num_mask = 0x1f;
191 dev->mii.phy_id = R815x_PHY_ID;
192 dev->mii.supports_gmii = 0;
193
194 return status;
195}
196
197static const struct driver_info r8152_info = {
198 .description = "RTL8152 ECM Device",
199 .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
200 .bind = r8152_bind,
201 .unbind = usbnet_cdc_unbind,
202 .status = usbnet_cdc_status,
203 .manage_power = usbnet_manage_power,
204};
205
206static const struct driver_info r8153_info = {
207 .description = "RTL8153 ECM Device",
208 .flags = FLAG_ETHER | FLAG_POINTTOPOINT,
209 .bind = r8153_bind,
210 .unbind = usbnet_cdc_unbind,
211 .status = usbnet_cdc_status,
212 .manage_power = usbnet_manage_power,
213};
214
215static const struct usb_device_id products[] = {
216{
217 USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
218 USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
219 .driver_info = (unsigned long) &r8152_info,
220},
221
222{
223 USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
224 USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
225 .driver_info = (unsigned long) &r8153_info,
226},
227
228 { }, /* END */
229};
230MODULE_DEVICE_TABLE(usb, products);
231
232static struct usb_driver r815x_driver = {
233 .name = "r815x",
234 .id_table = products,
235 .probe = usbnet_probe,
236 .disconnect = usbnet_disconnect,
237 .suspend = usbnet_suspend,
238 .resume = usbnet_resume,
239 .reset_resume = usbnet_resume,
240 .supports_autosuspend = 1,
241 .disable_hub_initiated_lpm = 1,
242};
243
244module_usb_driver(r815x_driver);
245
246MODULE_AUTHOR("Hayes Wang");
247MODULE_DESCRIPTION("Realtek USB ECM device");
248MODULE_LICENSE("GPL");