]>
Commit | Line | Data |
---|---|---|
82bcc200 AF |
1 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/asix_common.c backports-3.18.1-1/drivers/net/usb/asix_common.c |
2 | --- backports-3.18.1-1.org/drivers/net/usb/asix_common.c 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ backports-3.18.1-1/drivers/net/usb/asix_common.c 2014-12-16 18:39:45.000000000 +0100 | |
4 | @@ -0,0 +1,582 @@ | |
5 | +/* | |
6 | + * ASIX AX8817X based USB 2.0 Ethernet Devices | |
7 | + * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | |
8 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | |
9 | + * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | |
10 | + * Copyright (c) 2002-2003 TiVo Inc. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify | |
13 | + * it under the terms of the GNU General Public License as published by | |
14 | + * the Free Software Foundation; either version 2 of the License, or | |
15 | + * (at your option) any later version. | |
16 | + * | |
17 | + * This program is distributed in the hope that it will be useful, | |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | + * GNU General Public License for more details. | |
21 | + * | |
22 | + * You should have received a copy of the GNU General Public License | |
23 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
24 | + */ | |
25 | + | |
26 | +#include "asix.h" | |
27 | + | |
28 | +int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
29 | + u16 size, void *data) | |
30 | +{ | |
31 | + int ret; | |
32 | + ret = usbnet_read_cmd(dev, cmd, | |
33 | + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
34 | + value, index, data, size); | |
35 | + | |
36 | + if (ret != size && ret >= 0) | |
37 | + return -EINVAL; | |
38 | + return ret; | |
39 | +} | |
40 | + | |
41 | +int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
42 | + u16 size, void *data) | |
43 | +{ | |
44 | + return usbnet_write_cmd(dev, cmd, | |
45 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
46 | + value, index, data, size); | |
47 | +} | |
48 | + | |
49 | +void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
50 | + u16 size, void *data) | |
51 | +{ | |
52 | + usbnet_write_cmd_async(dev, cmd, | |
53 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
54 | + value, index, data, size); | |
55 | +} | |
56 | + | |
57 | +int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, | |
58 | + struct asix_rx_fixup_info *rx) | |
59 | +{ | |
60 | + int offset = 0; | |
61 | + | |
62 | + while (offset + sizeof(u16) <= skb->len) { | |
63 | + u16 remaining = 0; | |
64 | + unsigned char *data; | |
65 | + | |
66 | + if (!rx->size) { | |
67 | + if ((skb->len - offset == sizeof(u16)) || | |
68 | + rx->split_head) { | |
69 | + if(!rx->split_head) { | |
70 | + rx->header = get_unaligned_le16( | |
71 | + skb->data + offset); | |
72 | + rx->split_head = true; | |
73 | + offset += sizeof(u16); | |
74 | + break; | |
75 | + } else { | |
76 | + rx->header |= (get_unaligned_le16( | |
77 | + skb->data + offset) | |
78 | + << 16); | |
79 | + rx->split_head = false; | |
80 | + offset += sizeof(u16); | |
81 | + } | |
82 | + } else { | |
83 | + rx->header = get_unaligned_le32(skb->data + | |
84 | + offset); | |
85 | + offset += sizeof(u32); | |
86 | + } | |
87 | + | |
88 | + /* get the packet length */ | |
89 | + rx->size = (u16) (rx->header & 0x7ff); | |
90 | + if (rx->size != ((~rx->header >> 16) & 0x7ff)) { | |
91 | + netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n", | |
92 | + rx->header, offset); | |
93 | + rx->size = 0; | |
94 | + return 0; | |
95 | + } | |
96 | + rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, | |
97 | + rx->size); | |
98 | + if (!rx->ax_skb) | |
99 | + return 0; | |
100 | + } | |
101 | + | |
102 | + if (rx->size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) { | |
103 | + netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", | |
104 | + rx->size); | |
105 | + kfree_skb(rx->ax_skb); | |
106 | + rx->ax_skb = NULL; | |
107 | + rx->size = 0U; | |
108 | + | |
109 | + return 0; | |
110 | + } | |
111 | + | |
112 | + if (rx->size > skb->len - offset) { | |
113 | + remaining = rx->size - (skb->len - offset); | |
114 | + rx->size = skb->len - offset; | |
115 | + } | |
116 | + | |
117 | + data = skb_put(rx->ax_skb, rx->size); | |
118 | + memcpy(data, skb->data + offset, rx->size); | |
119 | + if (!remaining) | |
120 | + usbnet_skb_return(dev, rx->ax_skb); | |
121 | + | |
122 | + offset += (rx->size + 1) & 0xfffe; | |
123 | + rx->size = remaining; | |
124 | + } | |
125 | + | |
126 | + if (skb->len != offset) { | |
127 | + netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n", | |
128 | + skb->len, offset); | |
129 | + return 0; | |
130 | + } | |
131 | + | |
132 | + return 1; | |
133 | +} | |
134 | + | |
135 | +int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb) | |
136 | +{ | |
137 | + struct asix_common_private *dp = dev->driver_priv; | |
138 | + struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; | |
139 | + | |
140 | + return asix_rx_fixup_internal(dev, skb, rx); | |
141 | +} | |
142 | + | |
143 | +struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
144 | + gfp_t flags) | |
145 | +{ | |
146 | + int padlen; | |
147 | + int headroom = skb_headroom(skb); | |
148 | + int tailroom = skb_tailroom(skb); | |
149 | + u32 packet_len; | |
150 | + u32 padbytes = 0xffff0000; | |
151 | + | |
152 | + padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; | |
153 | + | |
154 | + /* We need to push 4 bytes in front of frame (packet_len) | |
155 | + * and maybe add 4 bytes after the end (if padlen is 4) | |
156 | + * | |
157 | + * Avoid skb_copy_expand() expensive call, using following rules : | |
158 | + * - We are allowed to push 4 bytes in headroom if skb_header_cloned() | |
159 | + * is false (and if we have 4 bytes of headroom) | |
160 | + * - We are allowed to put 4 bytes at tail if skb_cloned() | |
161 | + * is false (and if we have 4 bytes of tailroom) | |
162 | + * | |
163 | + * TCP packets for example are cloned, but skb_header_release() | |
164 | + * was called in tcp stack, allowing us to use headroom for our needs. | |
165 | + */ | |
166 | + if (!skb_header_cloned(skb) && | |
167 | + !(padlen && skb_cloned(skb)) && | |
168 | + headroom + tailroom >= 4 + padlen) { | |
169 | + /* following should not happen, but better be safe */ | |
170 | + if (headroom < 4 || | |
171 | + tailroom < padlen) { | |
172 | + skb->data = memmove(skb->head + 4, skb->data, skb->len); | |
173 | + skb_set_tail_pointer(skb, skb->len); | |
174 | + } | |
175 | + } else { | |
176 | + struct sk_buff *skb2; | |
177 | + | |
178 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); | |
179 | + dev_kfree_skb_any(skb); | |
180 | + skb = skb2; | |
181 | + if (!skb) | |
182 | + return NULL; | |
183 | + } | |
184 | + | |
185 | + packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len; | |
186 | + skb_push(skb, 4); | |
187 | + cpu_to_le32s(&packet_len); | |
188 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | |
189 | + | |
190 | + if (padlen) { | |
191 | + cpu_to_le32s(&padbytes); | |
192 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | |
193 | + skb_put(skb, sizeof(padbytes)); | |
194 | + } | |
195 | + return skb; | |
196 | +} | |
197 | + | |
198 | +int asix_set_sw_mii(struct usbnet *dev) | |
199 | +{ | |
200 | + int ret; | |
201 | + ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | |
202 | + if (ret < 0) | |
203 | + netdev_err(dev->net, "Failed to enable software MII access\n"); | |
204 | + return ret; | |
205 | +} | |
206 | + | |
207 | +int asix_set_hw_mii(struct usbnet *dev) | |
208 | +{ | |
209 | + int ret; | |
210 | + ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | |
211 | + if (ret < 0) | |
212 | + netdev_err(dev->net, "Failed to enable hardware MII access\n"); | |
213 | + return ret; | |
214 | +} | |
215 | + | |
216 | +int asix_read_phy_addr(struct usbnet *dev, int internal) | |
217 | +{ | |
218 | + int offset = (internal ? 1 : 0); | |
219 | + u8 buf[2]; | |
220 | + int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); | |
221 | + | |
222 | + netdev_dbg(dev->net, "asix_get_phy_addr()\n"); | |
223 | + | |
224 | + if (ret < 0) { | |
225 | + netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); | |
226 | + goto out; | |
227 | + } | |
228 | + netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", | |
229 | + *((__le16 *)buf)); | |
230 | + ret = buf[offset]; | |
231 | + | |
232 | +out: | |
233 | + return ret; | |
234 | +} | |
235 | + | |
236 | +int asix_get_phy_addr(struct usbnet *dev) | |
237 | +{ | |
238 | + /* return the address of the internal phy */ | |
239 | + return asix_read_phy_addr(dev, 1); | |
240 | +} | |
241 | + | |
242 | + | |
243 | +int asix_sw_reset(struct usbnet *dev, u8 flags) | |
244 | +{ | |
245 | + int ret; | |
246 | + | |
247 | + ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); | |
248 | + if (ret < 0) | |
249 | + netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); | |
250 | + | |
251 | + return ret; | |
252 | +} | |
253 | + | |
254 | +u16 asix_read_rx_ctl(struct usbnet *dev) | |
255 | +{ | |
256 | + __le16 v; | |
257 | + int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); | |
258 | + | |
259 | + if (ret < 0) { | |
260 | + netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); | |
261 | + goto out; | |
262 | + } | |
263 | + ret = le16_to_cpu(v); | |
264 | +out: | |
265 | + return ret; | |
266 | +} | |
267 | + | |
268 | +int asix_write_rx_ctl(struct usbnet *dev, u16 mode) | |
269 | +{ | |
270 | + int ret; | |
271 | + | |
272 | + netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); | |
273 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | |
274 | + if (ret < 0) | |
275 | + netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", | |
276 | + mode, ret); | |
277 | + | |
278 | + return ret; | |
279 | +} | |
280 | + | |
281 | +u16 asix_read_medium_status(struct usbnet *dev) | |
282 | +{ | |
283 | + __le16 v; | |
284 | + int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | |
285 | + | |
286 | + if (ret < 0) { | |
287 | + netdev_err(dev->net, "Error reading Medium Status register: %02x\n", | |
288 | + ret); | |
289 | + return ret; /* TODO: callers not checking for error ret */ | |
290 | + } | |
291 | + | |
292 | + return le16_to_cpu(v); | |
293 | + | |
294 | +} | |
295 | + | |
296 | +int asix_write_medium_mode(struct usbnet *dev, u16 mode) | |
297 | +{ | |
298 | + int ret; | |
299 | + | |
300 | + netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); | |
301 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | |
302 | + if (ret < 0) | |
303 | + netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", | |
304 | + mode, ret); | |
305 | + | |
306 | + return ret; | |
307 | +} | |
308 | + | |
309 | +int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) | |
310 | +{ | |
311 | + int ret; | |
312 | + | |
313 | + netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); | |
314 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); | |
315 | + if (ret < 0) | |
316 | + netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", | |
317 | + value, ret); | |
318 | + | |
319 | + if (sleep) | |
320 | + msleep(sleep); | |
321 | + | |
322 | + return ret; | |
323 | +} | |
324 | + | |
325 | +/* | |
326 | + * AX88772 & AX88178 have a 16-bit RX_CTL value | |
327 | + */ | |
328 | +void asix_set_multicast(struct net_device *net) | |
329 | +{ | |
330 | + struct usbnet *dev = netdev_priv(net); | |
331 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
332 | + u16 rx_ctl = AX_DEFAULT_RX_CTL; | |
333 | + | |
334 | + if (net->flags & IFF_PROMISC) { | |
335 | + rx_ctl |= AX_RX_CTL_PRO; | |
336 | + } else if (net->flags & IFF_ALLMULTI || | |
337 | + netdev_mc_count(net) > AX_MAX_MCAST) { | |
338 | + rx_ctl |= AX_RX_CTL_AMALL; | |
339 | + } else if (netdev_mc_empty(net)) { | |
340 | + /* just broadcast and directed */ | |
341 | + } else { | |
342 | + /* We use the 20 byte dev->data | |
343 | + * for our 8 byte filter buffer | |
344 | + * to avoid allocating memory that | |
345 | + * is tricky to free later */ | |
346 | + struct netdev_hw_addr *ha; | |
347 | + u32 crc_bits; | |
348 | + | |
349 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | |
350 | + | |
351 | + /* Build the multicast hash filter. */ | |
352 | + netdev_for_each_mc_addr(ha, net) { | |
353 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
354 | + data->multi_filter[crc_bits >> 3] |= | |
355 | + 1 << (crc_bits & 7); | |
356 | + } | |
357 | + | |
358 | + asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | |
359 | + AX_MCAST_FILTER_SIZE, data->multi_filter); | |
360 | + | |
361 | + rx_ctl |= AX_RX_CTL_AM; | |
362 | + } | |
363 | + | |
364 | + asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | |
365 | +} | |
366 | + | |
367 | +int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) | |
368 | +{ | |
369 | + struct usbnet *dev = netdev_priv(netdev); | |
370 | + __le16 res; | |
371 | + | |
372 | + mutex_lock(&dev->phy_mutex); | |
373 | + asix_set_sw_mii(dev); | |
374 | + asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, | |
375 | + (__u16)loc, 2, &res); | |
376 | + asix_set_hw_mii(dev); | |
377 | + mutex_unlock(&dev->phy_mutex); | |
378 | + | |
379 | + netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | |
380 | + phy_id, loc, le16_to_cpu(res)); | |
381 | + | |
382 | + return le16_to_cpu(res); | |
383 | +} | |
384 | + | |
385 | +void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) | |
386 | +{ | |
387 | + struct usbnet *dev = netdev_priv(netdev); | |
388 | + __le16 res = cpu_to_le16(val); | |
389 | + | |
390 | + netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | |
391 | + phy_id, loc, val); | |
392 | + mutex_lock(&dev->phy_mutex); | |
393 | + asix_set_sw_mii(dev); | |
394 | + asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | |
395 | + asix_set_hw_mii(dev); | |
396 | + mutex_unlock(&dev->phy_mutex); | |
397 | +} | |
398 | + | |
399 | +void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
400 | +{ | |
401 | + struct usbnet *dev = netdev_priv(net); | |
402 | + u8 opt; | |
403 | + | |
404 | + if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | |
405 | + wolinfo->supported = 0; | |
406 | + wolinfo->wolopts = 0; | |
407 | + return; | |
408 | + } | |
409 | + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | |
410 | + wolinfo->wolopts = 0; | |
411 | + if (opt & AX_MONITOR_LINK) | |
412 | + wolinfo->wolopts |= WAKE_PHY; | |
413 | + if (opt & AX_MONITOR_MAGIC) | |
414 | + wolinfo->wolopts |= WAKE_MAGIC; | |
415 | +} | |
416 | + | |
417 | +int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
418 | +{ | |
419 | + struct usbnet *dev = netdev_priv(net); | |
420 | + u8 opt = 0; | |
421 | + | |
422 | + if (wolinfo->wolopts & WAKE_PHY) | |
423 | + opt |= AX_MONITOR_LINK; | |
424 | + if (wolinfo->wolopts & WAKE_MAGIC) | |
425 | + opt |= AX_MONITOR_MAGIC; | |
426 | + | |
427 | + if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, | |
428 | + opt, 0, 0, NULL) < 0) | |
429 | + return -EINVAL; | |
430 | + | |
431 | + return 0; | |
432 | +} | |
433 | + | |
434 | +int asix_get_eeprom_len(struct net_device *net) | |
435 | +{ | |
436 | + return AX_EEPROM_LEN; | |
437 | +} | |
438 | + | |
439 | +int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |
440 | + u8 *data) | |
441 | +{ | |
442 | + struct usbnet *dev = netdev_priv(net); | |
443 | + u16 *eeprom_buff; | |
444 | + int first_word, last_word; | |
445 | + int i; | |
446 | + | |
447 | + if (eeprom->len == 0) | |
448 | + return -EINVAL; | |
449 | + | |
450 | + eeprom->magic = AX_EEPROM_MAGIC; | |
451 | + | |
452 | + first_word = eeprom->offset >> 1; | |
453 | + last_word = (eeprom->offset + eeprom->len - 1) >> 1; | |
454 | + | |
455 | + eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | |
456 | + GFP_KERNEL); | |
457 | + if (!eeprom_buff) | |
458 | + return -ENOMEM; | |
459 | + | |
460 | + /* ax8817x returns 2 bytes from eeprom on read */ | |
461 | + for (i = first_word; i <= last_word; i++) { | |
462 | + if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2, | |
463 | + &(eeprom_buff[i - first_word])) < 0) { | |
464 | + kfree(eeprom_buff); | |
465 | + return -EIO; | |
466 | + } | |
467 | + } | |
468 | + | |
469 | + memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); | |
470 | + kfree(eeprom_buff); | |
471 | + return 0; | |
472 | +} | |
473 | + | |
474 | +int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |
475 | + u8 *data) | |
476 | +{ | |
477 | + struct usbnet *dev = netdev_priv(net); | |
478 | + u16 *eeprom_buff; | |
479 | + int first_word, last_word; | |
480 | + int i; | |
481 | + int ret; | |
482 | + | |
483 | + netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n", | |
484 | + eeprom->len, eeprom->offset, eeprom->magic); | |
485 | + | |
486 | + if (eeprom->len == 0) | |
487 | + return -EINVAL; | |
488 | + | |
489 | + if (eeprom->magic != AX_EEPROM_MAGIC) | |
490 | + return -EINVAL; | |
491 | + | |
492 | + first_word = eeprom->offset >> 1; | |
493 | + last_word = (eeprom->offset + eeprom->len - 1) >> 1; | |
494 | + | |
495 | + eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | |
496 | + GFP_KERNEL); | |
497 | + if (!eeprom_buff) | |
498 | + return -ENOMEM; | |
499 | + | |
500 | + /* align data to 16 bit boundaries, read the missing data from | |
501 | + the EEPROM */ | |
502 | + if (eeprom->offset & 1) { | |
503 | + ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2, | |
504 | + &(eeprom_buff[0])); | |
505 | + if (ret < 0) { | |
506 | + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); | |
507 | + goto free; | |
508 | + } | |
509 | + } | |
510 | + | |
511 | + if ((eeprom->offset + eeprom->len) & 1) { | |
512 | + ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2, | |
513 | + &(eeprom_buff[last_word - first_word])); | |
514 | + if (ret < 0) { | |
515 | + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); | |
516 | + goto free; | |
517 | + } | |
518 | + } | |
519 | + | |
520 | + memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); | |
521 | + | |
522 | + /* write data to EEPROM */ | |
523 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL); | |
524 | + if (ret < 0) { | |
525 | + netdev_err(net, "Failed to enable EEPROM write\n"); | |
526 | + goto free; | |
527 | + } | |
528 | + msleep(20); | |
529 | + | |
530 | + for (i = first_word; i <= last_word; i++) { | |
531 | + netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", | |
532 | + i, eeprom_buff[i - first_word]); | |
533 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, | |
534 | + eeprom_buff[i - first_word], 0, NULL); | |
535 | + if (ret < 0) { | |
536 | + netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", | |
537 | + i); | |
538 | + goto free; | |
539 | + } | |
540 | + msleep(20); | |
541 | + } | |
542 | + | |
543 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL); | |
544 | + if (ret < 0) { | |
545 | + netdev_err(net, "Failed to disable EEPROM write\n"); | |
546 | + goto free; | |
547 | + } | |
548 | + | |
549 | + ret = 0; | |
550 | +free: | |
551 | + kfree(eeprom_buff); | |
552 | + return ret; | |
553 | +} | |
554 | + | |
555 | +void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | |
556 | +{ | |
557 | + /* Inherit standard device info */ | |
558 | + usbnet_get_drvinfo(net, info); | |
559 | + strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); | |
560 | + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
561 | + info->eedump_len = AX_EEPROM_LEN; | |
562 | +} | |
563 | + | |
564 | +int asix_set_mac_address(struct net_device *net, void *p) | |
565 | +{ | |
566 | + struct usbnet *dev = netdev_priv(net); | |
567 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
568 | + struct sockaddr *addr = p; | |
569 | + | |
570 | + if (netif_running(net)) | |
571 | + return -EBUSY; | |
572 | + if (!is_valid_ether_addr(addr->sa_data)) | |
573 | + return -EADDRNOTAVAIL; | |
574 | + | |
575 | + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | |
576 | + | |
577 | + /* We use the 20 byte dev->data | |
578 | + * for our 6 byte mac buffer | |
579 | + * to avoid allocating memory that | |
580 | + * is tricky to free later */ | |
581 | + memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | |
582 | + asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
583 | + data->mac_addr); | |
584 | + | |
585 | + return 0; | |
586 | +} | |
587 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/asix_devices.c backports-3.18.1-1/drivers/net/usb/asix_devices.c | |
588 | --- backports-3.18.1-1.org/drivers/net/usb/asix_devices.c 1970-01-01 01:00:00.000000000 +0100 | |
589 | +++ backports-3.18.1-1/drivers/net/usb/asix_devices.c 2014-12-16 18:39:45.000000000 +0100 | |
590 | @@ -0,0 +1,1104 @@ | |
591 | +/* | |
592 | + * ASIX AX8817X based USB 2.0 Ethernet Devices | |
593 | + * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | |
594 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | |
595 | + * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | |
596 | + * Copyright (c) 2002-2003 TiVo Inc. | |
597 | + * | |
598 | + * This program is free software; you can redistribute it and/or modify | |
599 | + * it under the terms of the GNU General Public License as published by | |
600 | + * the Free Software Foundation; either version 2 of the License, or | |
601 | + * (at your option) any later version. | |
602 | + * | |
603 | + * This program is distributed in the hope that it will be useful, | |
604 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
605 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
606 | + * GNU General Public License for more details. | |
607 | + * | |
608 | + * You should have received a copy of the GNU General Public License | |
609 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
610 | + */ | |
611 | + | |
612 | +#include "asix.h" | |
613 | + | |
614 | +#define PHY_MODE_MARVELL 0x0000 | |
615 | +#define MII_MARVELL_LED_CTRL 0x0018 | |
616 | +#define MII_MARVELL_STATUS 0x001b | |
617 | +#define MII_MARVELL_CTRL 0x0014 | |
618 | + | |
619 | +#define MARVELL_LED_MANUAL 0x0019 | |
620 | + | |
621 | +#define MARVELL_STATUS_HWCFG 0x0004 | |
622 | + | |
623 | +#define MARVELL_CTRL_TXDELAY 0x0002 | |
624 | +#define MARVELL_CTRL_RXDELAY 0x0080 | |
625 | + | |
626 | +#define PHY_MODE_RTL8211CL 0x000C | |
627 | + | |
628 | +struct ax88172_int_data { | |
629 | + __le16 res1; | |
630 | + u8 link; | |
631 | + __le16 res2; | |
632 | + u8 status; | |
633 | + __le16 res3; | |
634 | +} __packed; | |
635 | + | |
636 | +static void asix_status(struct usbnet *dev, struct urb *urb) | |
637 | +{ | |
638 | + struct ax88172_int_data *event; | |
639 | + int link; | |
640 | + | |
641 | + if (urb->actual_length < 8) | |
642 | + return; | |
643 | + | |
644 | + event = urb->transfer_buffer; | |
645 | + link = event->link & 0x01; | |
646 | + if (netif_carrier_ok(dev->net) != link) { | |
647 | + usbnet_link_change(dev, link, 1); | |
648 | + netdev_dbg(dev->net, "Link Status is: %d\n", link); | |
649 | + } | |
650 | +} | |
651 | + | |
652 | +static void asix_set_netdev_dev_addr(struct usbnet *dev, u8 *addr) | |
653 | +{ | |
654 | + if (is_valid_ether_addr(addr)) { | |
655 | + memcpy(dev->net->dev_addr, addr, ETH_ALEN); | |
656 | + } else { | |
657 | + netdev_info(dev->net, "invalid hw address, using random\n"); | |
658 | + eth_hw_addr_random(dev->net); | |
659 | + } | |
660 | +} | |
661 | + | |
662 | +/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | |
663 | +static u32 asix_get_phyid(struct usbnet *dev) | |
664 | +{ | |
665 | + int phy_reg; | |
666 | + u32 phy_id; | |
667 | + int i; | |
668 | + | |
669 | + /* Poll for the rare case the FW or phy isn't ready yet. */ | |
670 | + for (i = 0; i < 100; i++) { | |
671 | + phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | |
672 | + if (phy_reg != 0 && phy_reg != 0xFFFF) | |
673 | + break; | |
674 | + mdelay(1); | |
675 | + } | |
676 | + | |
677 | + if (phy_reg <= 0 || phy_reg == 0xFFFF) | |
678 | + return 0; | |
679 | + | |
680 | + phy_id = (phy_reg & 0xffff) << 16; | |
681 | + | |
682 | + phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | |
683 | + if (phy_reg < 0) | |
684 | + return 0; | |
685 | + | |
686 | + phy_id |= (phy_reg & 0xffff); | |
687 | + | |
688 | + return phy_id; | |
689 | +} | |
690 | + | |
691 | +static u32 asix_get_link(struct net_device *net) | |
692 | +{ | |
693 | + struct usbnet *dev = netdev_priv(net); | |
694 | + | |
695 | + return mii_link_ok(&dev->mii); | |
696 | +} | |
697 | + | |
698 | +static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) | |
699 | +{ | |
700 | + struct usbnet *dev = netdev_priv(net); | |
701 | + | |
702 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
703 | +} | |
704 | + | |
705 | +/* We need to override some ethtool_ops so we require our | |
706 | + own structure so we don't interfere with other usbnet | |
707 | + devices that may be connected at the same time. */ | |
708 | +static const struct ethtool_ops ax88172_ethtool_ops = { | |
709 | + .get_drvinfo = asix_get_drvinfo, | |
710 | + .get_link = asix_get_link, | |
711 | + .get_msglevel = usbnet_get_msglevel, | |
712 | + .set_msglevel = usbnet_set_msglevel, | |
713 | + .get_wol = asix_get_wol, | |
714 | + .set_wol = asix_set_wol, | |
715 | + .get_eeprom_len = asix_get_eeprom_len, | |
716 | + .get_eeprom = asix_get_eeprom, | |
717 | + .set_eeprom = asix_set_eeprom, | |
718 | + .get_settings = usbnet_get_settings, | |
719 | + .set_settings = usbnet_set_settings, | |
720 | + .nway_reset = usbnet_nway_reset, | |
721 | +}; | |
722 | + | |
723 | +static void ax88172_set_multicast(struct net_device *net) | |
724 | +{ | |
725 | + struct usbnet *dev = netdev_priv(net); | |
726 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
727 | + u8 rx_ctl = 0x8c; | |
728 | + | |
729 | + if (net->flags & IFF_PROMISC) { | |
730 | + rx_ctl |= 0x01; | |
731 | + } else if (net->flags & IFF_ALLMULTI || | |
732 | + netdev_mc_count(net) > AX_MAX_MCAST) { | |
733 | + rx_ctl |= 0x02; | |
734 | + } else if (netdev_mc_empty(net)) { | |
735 | + /* just broadcast and directed */ | |
736 | + } else { | |
737 | + /* We use the 20 byte dev->data | |
738 | + * for our 8 byte filter buffer | |
739 | + * to avoid allocating memory that | |
740 | + * is tricky to free later */ | |
741 | + struct netdev_hw_addr *ha; | |
742 | + u32 crc_bits; | |
743 | + | |
744 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); | |
745 | + | |
746 | + /* Build the multicast hash filter. */ | |
747 | + netdev_for_each_mc_addr(ha, net) { | |
748 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
749 | + data->multi_filter[crc_bits >> 3] |= | |
750 | + 1 << (crc_bits & 7); | |
751 | + } | |
752 | + | |
753 | + asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, | |
754 | + AX_MCAST_FILTER_SIZE, data->multi_filter); | |
755 | + | |
756 | + rx_ctl |= 0x10; | |
757 | + } | |
758 | + | |
759 | + asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | |
760 | +} | |
761 | + | |
762 | +static int ax88172_link_reset(struct usbnet *dev) | |
763 | +{ | |
764 | + u8 mode; | |
765 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
766 | + | |
767 | + mii_check_media(&dev->mii, 1, 1); | |
768 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
769 | + mode = AX88172_MEDIUM_DEFAULT; | |
770 | + | |
771 | + if (ecmd.duplex != DUPLEX_FULL) | |
772 | + mode |= ~AX88172_MEDIUM_FD; | |
773 | + | |
774 | + netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | |
775 | + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | |
776 | + | |
777 | + asix_write_medium_mode(dev, mode); | |
778 | + | |
779 | + return 0; | |
780 | +} | |
781 | + | |
782 | +static const struct net_device_ops ax88172_netdev_ops = { | |
783 | + .ndo_open = usbnet_open, | |
784 | + .ndo_stop = usbnet_stop, | |
785 | + .ndo_start_xmit = usbnet_start_xmit, | |
786 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
787 | + .ndo_change_mtu = usbnet_change_mtu, | |
788 | + .ndo_set_mac_address = eth_mac_addr, | |
789 | + .ndo_validate_addr = eth_validate_addr, | |
790 | + .ndo_do_ioctl = asix_ioctl, | |
791 | + .ndo_set_rx_mode = ax88172_set_multicast, | |
792 | +}; | |
793 | + | |
794 | +static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) | |
795 | +{ | |
796 | + int ret = 0; | |
797 | + u8 buf[ETH_ALEN]; | |
798 | + int i; | |
799 | + unsigned long gpio_bits = dev->driver_info->data; | |
800 | + | |
801 | + usbnet_get_endpoints(dev,intf); | |
802 | + | |
803 | + /* Toggle the GPIOs in a manufacturer/model specific way */ | |
804 | + for (i = 2; i >= 0; i--) { | |
805 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, | |
806 | + (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); | |
807 | + if (ret < 0) | |
808 | + goto out; | |
809 | + msleep(5); | |
810 | + } | |
811 | + | |
812 | + ret = asix_write_rx_ctl(dev, 0x80); | |
813 | + if (ret < 0) | |
814 | + goto out; | |
815 | + | |
816 | + /* Get the MAC address */ | |
817 | + ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | |
818 | + if (ret < 0) { | |
819 | + netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n", | |
820 | + ret); | |
821 | + goto out; | |
822 | + } | |
823 | + | |
824 | + asix_set_netdev_dev_addr(dev, buf); | |
825 | + | |
826 | + /* Initialize MII structure */ | |
827 | + dev->mii.dev = dev->net; | |
828 | + dev->mii.mdio_read = asix_mdio_read; | |
829 | + dev->mii.mdio_write = asix_mdio_write; | |
830 | + dev->mii.phy_id_mask = 0x3f; | |
831 | + dev->mii.reg_num_mask = 0x1f; | |
832 | + dev->mii.phy_id = asix_get_phy_addr(dev); | |
833 | + | |
834 | + dev->net->netdev_ops = &ax88172_netdev_ops; | |
835 | + dev->net->ethtool_ops = &ax88172_ethtool_ops; | |
836 | + dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | |
837 | + dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | |
838 | + | |
839 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
840 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
841 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | |
842 | + mii_nway_restart(&dev->mii); | |
843 | + | |
844 | + return 0; | |
845 | + | |
846 | +out: | |
847 | + return ret; | |
848 | +} | |
849 | + | |
850 | +static const struct ethtool_ops ax88772_ethtool_ops = { | |
851 | + .get_drvinfo = asix_get_drvinfo, | |
852 | + .get_link = asix_get_link, | |
853 | + .get_msglevel = usbnet_get_msglevel, | |
854 | + .set_msglevel = usbnet_set_msglevel, | |
855 | + .get_wol = asix_get_wol, | |
856 | + .set_wol = asix_set_wol, | |
857 | + .get_eeprom_len = asix_get_eeprom_len, | |
858 | + .get_eeprom = asix_get_eeprom, | |
859 | + .set_eeprom = asix_set_eeprom, | |
860 | + .get_settings = usbnet_get_settings, | |
861 | + .set_settings = usbnet_set_settings, | |
862 | + .nway_reset = usbnet_nway_reset, | |
863 | +}; | |
864 | + | |
865 | +static int ax88772_link_reset(struct usbnet *dev) | |
866 | +{ | |
867 | + u16 mode; | |
868 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
869 | + | |
870 | + mii_check_media(&dev->mii, 1, 1); | |
871 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
872 | + mode = AX88772_MEDIUM_DEFAULT; | |
873 | + | |
874 | + if (ethtool_cmd_speed(&ecmd) != SPEED_100) | |
875 | + mode &= ~AX_MEDIUM_PS; | |
876 | + | |
877 | + if (ecmd.duplex != DUPLEX_FULL) | |
878 | + mode &= ~AX_MEDIUM_FD; | |
879 | + | |
880 | + netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | |
881 | + ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | |
882 | + | |
883 | + asix_write_medium_mode(dev, mode); | |
884 | + | |
885 | + return 0; | |
886 | +} | |
887 | + | |
888 | +static int ax88772_reset(struct usbnet *dev) | |
889 | +{ | |
890 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
891 | + int ret, embd_phy; | |
892 | + u16 rx_ctl; | |
893 | + | |
894 | + ret = asix_write_gpio(dev, | |
895 | + AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); | |
896 | + if (ret < 0) | |
897 | + goto out; | |
898 | + | |
899 | + embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | |
900 | + | |
901 | + ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | |
902 | + if (ret < 0) { | |
903 | + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | |
904 | + goto out; | |
905 | + } | |
906 | + | |
907 | + ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); | |
908 | + if (ret < 0) | |
909 | + goto out; | |
910 | + | |
911 | + msleep(150); | |
912 | + | |
913 | + ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | |
914 | + if (ret < 0) | |
915 | + goto out; | |
916 | + | |
917 | + msleep(150); | |
918 | + | |
919 | + if (embd_phy) { | |
920 | + ret = asix_sw_reset(dev, AX_SWRESET_IPRL); | |
921 | + if (ret < 0) | |
922 | + goto out; | |
923 | + } else { | |
924 | + ret = asix_sw_reset(dev, AX_SWRESET_PRTE); | |
925 | + if (ret < 0) | |
926 | + goto out; | |
927 | + } | |
928 | + | |
929 | + msleep(150); | |
930 | + rx_ctl = asix_read_rx_ctl(dev); | |
931 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | |
932 | + ret = asix_write_rx_ctl(dev, 0x0000); | |
933 | + if (ret < 0) | |
934 | + goto out; | |
935 | + | |
936 | + rx_ctl = asix_read_rx_ctl(dev); | |
937 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | |
938 | + | |
939 | + ret = asix_sw_reset(dev, AX_SWRESET_PRL); | |
940 | + if (ret < 0) | |
941 | + goto out; | |
942 | + | |
943 | + msleep(150); | |
944 | + | |
945 | + ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); | |
946 | + if (ret < 0) | |
947 | + goto out; | |
948 | + | |
949 | + msleep(150); | |
950 | + | |
951 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
952 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
953 | + ADVERTISE_ALL | ADVERTISE_CSMA); | |
954 | + mii_nway_restart(&dev->mii); | |
955 | + | |
956 | + ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); | |
957 | + if (ret < 0) | |
958 | + goto out; | |
959 | + | |
960 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | |
961 | + AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | |
962 | + AX88772_IPG2_DEFAULT, 0, NULL); | |
963 | + if (ret < 0) { | |
964 | + netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); | |
965 | + goto out; | |
966 | + } | |
967 | + | |
968 | + /* Rewrite MAC address */ | |
969 | + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | |
970 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
971 | + data->mac_addr); | |
972 | + if (ret < 0) | |
973 | + goto out; | |
974 | + | |
975 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | |
976 | + ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | |
977 | + if (ret < 0) | |
978 | + goto out; | |
979 | + | |
980 | + rx_ctl = asix_read_rx_ctl(dev); | |
981 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", | |
982 | + rx_ctl); | |
983 | + | |
984 | + rx_ctl = asix_read_medium_status(dev); | |
985 | + netdev_dbg(dev->net, | |
986 | + "Medium Status is 0x%04x after all initializations\n", | |
987 | + rx_ctl); | |
988 | + | |
989 | + return 0; | |
990 | + | |
991 | +out: | |
992 | + return ret; | |
993 | + | |
994 | +} | |
995 | + | |
996 | +static const struct net_device_ops ax88772_netdev_ops = { | |
997 | + .ndo_open = usbnet_open, | |
998 | + .ndo_stop = usbnet_stop, | |
999 | + .ndo_start_xmit = usbnet_start_xmit, | |
1000 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
1001 | + .ndo_change_mtu = usbnet_change_mtu, | |
1002 | + .ndo_set_mac_address = asix_set_mac_address, | |
1003 | + .ndo_validate_addr = eth_validate_addr, | |
1004 | + .ndo_do_ioctl = asix_ioctl, | |
1005 | + .ndo_set_rx_mode = asix_set_multicast, | |
1006 | +}; | |
1007 | + | |
1008 | +static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | |
1009 | +{ | |
1010 | + int ret, embd_phy, i; | |
1011 | + u8 buf[ETH_ALEN]; | |
1012 | + u32 phyid; | |
1013 | + | |
1014 | + usbnet_get_endpoints(dev,intf); | |
1015 | + | |
1016 | + /* Get the MAC address */ | |
1017 | + if (dev->driver_info->data & FLAG_EEPROM_MAC) { | |
1018 | + for (i = 0; i < (ETH_ALEN >> 1); i++) { | |
1019 | + ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x04 + i, | |
1020 | + 0, 2, buf + i * 2); | |
1021 | + if (ret < 0) | |
1022 | + break; | |
1023 | + } | |
1024 | + } else { | |
1025 | + ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, | |
1026 | + 0, 0, ETH_ALEN, buf); | |
1027 | + } | |
1028 | + | |
1029 | + if (ret < 0) { | |
1030 | + netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); | |
1031 | + return ret; | |
1032 | + } | |
1033 | + | |
1034 | + asix_set_netdev_dev_addr(dev, buf); | |
1035 | + | |
1036 | + /* Initialize MII structure */ | |
1037 | + dev->mii.dev = dev->net; | |
1038 | + dev->mii.mdio_read = asix_mdio_read; | |
1039 | + dev->mii.mdio_write = asix_mdio_write; | |
1040 | + dev->mii.phy_id_mask = 0x1f; | |
1041 | + dev->mii.reg_num_mask = 0x1f; | |
1042 | + dev->mii.phy_id = asix_get_phy_addr(dev); | |
1043 | + | |
1044 | + dev->net->netdev_ops = &ax88772_netdev_ops; | |
1045 | + dev->net->ethtool_ops = &ax88772_ethtool_ops; | |
1046 | + dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ | |
1047 | + dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ | |
1048 | + | |
1049 | + embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | |
1050 | + | |
1051 | + /* Reset the PHY to normal operation mode */ | |
1052 | + ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | |
1053 | + if (ret < 0) { | |
1054 | + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | |
1055 | + return ret; | |
1056 | + } | |
1057 | + | |
1058 | + ax88772_reset(dev); | |
1059 | + | |
1060 | + /* Read PHYID register *AFTER* the PHY was reset properly */ | |
1061 | + phyid = asix_get_phyid(dev); | |
1062 | + netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); | |
1063 | + | |
1064 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | |
1065 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { | |
1066 | + /* hard_mtu is still the default - the device does not support | |
1067 | + jumbo eth frames */ | |
1068 | + dev->rx_urb_size = 2048; | |
1069 | + } | |
1070 | + | |
1071 | + dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); | |
1072 | + if (!dev->driver_priv) | |
1073 | + return -ENOMEM; | |
1074 | + | |
1075 | + return 0; | |
1076 | +} | |
1077 | + | |
1078 | +static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) | |
1079 | +{ | |
1080 | + if (dev->driver_priv) | |
1081 | + kfree(dev->driver_priv); | |
1082 | +} | |
1083 | + | |
1084 | +static const struct ethtool_ops ax88178_ethtool_ops = { | |
1085 | + .get_drvinfo = asix_get_drvinfo, | |
1086 | + .get_link = asix_get_link, | |
1087 | + .get_msglevel = usbnet_get_msglevel, | |
1088 | + .set_msglevel = usbnet_set_msglevel, | |
1089 | + .get_wol = asix_get_wol, | |
1090 | + .set_wol = asix_set_wol, | |
1091 | + .get_eeprom_len = asix_get_eeprom_len, | |
1092 | + .get_eeprom = asix_get_eeprom, | |
1093 | + .set_eeprom = asix_set_eeprom, | |
1094 | + .get_settings = usbnet_get_settings, | |
1095 | + .set_settings = usbnet_set_settings, | |
1096 | + .nway_reset = usbnet_nway_reset, | |
1097 | +}; | |
1098 | + | |
1099 | +static int marvell_phy_init(struct usbnet *dev) | |
1100 | +{ | |
1101 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
1102 | + u16 reg; | |
1103 | + | |
1104 | + netdev_dbg(dev->net, "marvell_phy_init()\n"); | |
1105 | + | |
1106 | + reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); | |
1107 | + netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); | |
1108 | + | |
1109 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, | |
1110 | + MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); | |
1111 | + | |
1112 | + if (data->ledmode) { | |
1113 | + reg = asix_mdio_read(dev->net, dev->mii.phy_id, | |
1114 | + MII_MARVELL_LED_CTRL); | |
1115 | + netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); | |
1116 | + | |
1117 | + reg &= 0xf8ff; | |
1118 | + reg |= (1 + 0x0100); | |
1119 | + asix_mdio_write(dev->net, dev->mii.phy_id, | |
1120 | + MII_MARVELL_LED_CTRL, reg); | |
1121 | + | |
1122 | + reg = asix_mdio_read(dev->net, dev->mii.phy_id, | |
1123 | + MII_MARVELL_LED_CTRL); | |
1124 | + netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); | |
1125 | + reg &= 0xfc0f; | |
1126 | + } | |
1127 | + | |
1128 | + return 0; | |
1129 | +} | |
1130 | + | |
1131 | +static int rtl8211cl_phy_init(struct usbnet *dev) | |
1132 | +{ | |
1133 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
1134 | + | |
1135 | + netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); | |
1136 | + | |
1137 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); | |
1138 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); | |
1139 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, | |
1140 | + asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); | |
1141 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | |
1142 | + | |
1143 | + if (data->ledmode == 12) { | |
1144 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); | |
1145 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); | |
1146 | + asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); | |
1147 | + } | |
1148 | + | |
1149 | + return 0; | |
1150 | +} | |
1151 | + | |
1152 | +static int marvell_led_status(struct usbnet *dev, u16 speed) | |
1153 | +{ | |
1154 | + u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); | |
1155 | + | |
1156 | + netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); | |
1157 | + | |
1158 | + /* Clear out the center LED bits - 0x03F0 */ | |
1159 | + reg &= 0xfc0f; | |
1160 | + | |
1161 | + switch (speed) { | |
1162 | + case SPEED_1000: | |
1163 | + reg |= 0x03e0; | |
1164 | + break; | |
1165 | + case SPEED_100: | |
1166 | + reg |= 0x03b0; | |
1167 | + break; | |
1168 | + default: | |
1169 | + reg |= 0x02f0; | |
1170 | + } | |
1171 | + | |
1172 | + netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); | |
1173 | + asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); | |
1174 | + | |
1175 | + return 0; | |
1176 | +} | |
1177 | + | |
1178 | +static int ax88178_reset(struct usbnet *dev) | |
1179 | +{ | |
1180 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
1181 | + int ret; | |
1182 | + __le16 eeprom; | |
1183 | + u8 status; | |
1184 | + int gpio0 = 0; | |
1185 | + u32 phyid; | |
1186 | + | |
1187 | + asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); | |
1188 | + netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status); | |
1189 | + | |
1190 | + asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); | |
1191 | + asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); | |
1192 | + asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); | |
1193 | + | |
1194 | + netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom); | |
1195 | + | |
1196 | + if (eeprom == cpu_to_le16(0xffff)) { | |
1197 | + data->phymode = PHY_MODE_MARVELL; | |
1198 | + data->ledmode = 0; | |
1199 | + gpio0 = 1; | |
1200 | + } else { | |
1201 | + data->phymode = le16_to_cpu(eeprom) & 0x7F; | |
1202 | + data->ledmode = le16_to_cpu(eeprom) >> 8; | |
1203 | + gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; | |
1204 | + } | |
1205 | + netdev_dbg(dev->net, "GPIO0: %d, PhyMode: %d\n", gpio0, data->phymode); | |
1206 | + | |
1207 | + /* Power up external GigaPHY through AX88178 GPIO pin */ | |
1208 | + asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); | |
1209 | + if ((le16_to_cpu(eeprom) >> 8) != 1) { | |
1210 | + asix_write_gpio(dev, 0x003c, 30); | |
1211 | + asix_write_gpio(dev, 0x001c, 300); | |
1212 | + asix_write_gpio(dev, 0x003c, 30); | |
1213 | + } else { | |
1214 | + netdev_dbg(dev->net, "gpio phymode == 1 path\n"); | |
1215 | + asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); | |
1216 | + asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); | |
1217 | + } | |
1218 | + | |
1219 | + /* Read PHYID register *AFTER* powering up PHY */ | |
1220 | + phyid = asix_get_phyid(dev); | |
1221 | + netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); | |
1222 | + | |
1223 | + /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ | |
1224 | + asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); | |
1225 | + | |
1226 | + asix_sw_reset(dev, 0); | |
1227 | + msleep(150); | |
1228 | + | |
1229 | + asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | |
1230 | + msleep(150); | |
1231 | + | |
1232 | + asix_write_rx_ctl(dev, 0); | |
1233 | + | |
1234 | + if (data->phymode == PHY_MODE_MARVELL) { | |
1235 | + marvell_phy_init(dev); | |
1236 | + msleep(60); | |
1237 | + } else if (data->phymode == PHY_MODE_RTL8211CL) | |
1238 | + rtl8211cl_phy_init(dev); | |
1239 | + | |
1240 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, | |
1241 | + BMCR_RESET | BMCR_ANENABLE); | |
1242 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
1243 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | |
1244 | + asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, | |
1245 | + ADVERTISE_1000FULL); | |
1246 | + | |
1247 | + mii_nway_restart(&dev->mii); | |
1248 | + | |
1249 | + ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); | |
1250 | + if (ret < 0) | |
1251 | + return ret; | |
1252 | + | |
1253 | + /* Rewrite MAC address */ | |
1254 | + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | |
1255 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
1256 | + data->mac_addr); | |
1257 | + if (ret < 0) | |
1258 | + return ret; | |
1259 | + | |
1260 | + ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | |
1261 | + if (ret < 0) | |
1262 | + return ret; | |
1263 | + | |
1264 | + return 0; | |
1265 | +} | |
1266 | + | |
1267 | +static int ax88178_link_reset(struct usbnet *dev) | |
1268 | +{ | |
1269 | + u16 mode; | |
1270 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
1271 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
1272 | + u32 speed; | |
1273 | + | |
1274 | + netdev_dbg(dev->net, "ax88178_link_reset()\n"); | |
1275 | + | |
1276 | + mii_check_media(&dev->mii, 1, 1); | |
1277 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
1278 | + mode = AX88178_MEDIUM_DEFAULT; | |
1279 | + speed = ethtool_cmd_speed(&ecmd); | |
1280 | + | |
1281 | + if (speed == SPEED_1000) | |
1282 | + mode |= AX_MEDIUM_GM; | |
1283 | + else if (speed == SPEED_100) | |
1284 | + mode |= AX_MEDIUM_PS; | |
1285 | + else | |
1286 | + mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); | |
1287 | + | |
1288 | + mode |= AX_MEDIUM_ENCK; | |
1289 | + | |
1290 | + if (ecmd.duplex == DUPLEX_FULL) | |
1291 | + mode |= AX_MEDIUM_FD; | |
1292 | + else | |
1293 | + mode &= ~AX_MEDIUM_FD; | |
1294 | + | |
1295 | + netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", | |
1296 | + speed, ecmd.duplex, mode); | |
1297 | + | |
1298 | + asix_write_medium_mode(dev, mode); | |
1299 | + | |
1300 | + if (data->phymode == PHY_MODE_MARVELL && data->ledmode) | |
1301 | + marvell_led_status(dev, speed); | |
1302 | + | |
1303 | + return 0; | |
1304 | +} | |
1305 | + | |
1306 | +static void ax88178_set_mfb(struct usbnet *dev) | |
1307 | +{ | |
1308 | + u16 mfb = AX_RX_CTL_MFB_16384; | |
1309 | + u16 rxctl; | |
1310 | + u16 medium; | |
1311 | + int old_rx_urb_size = dev->rx_urb_size; | |
1312 | + | |
1313 | + if (dev->hard_mtu < 2048) { | |
1314 | + dev->rx_urb_size = 2048; | |
1315 | + mfb = AX_RX_CTL_MFB_2048; | |
1316 | + } else if (dev->hard_mtu < 4096) { | |
1317 | + dev->rx_urb_size = 4096; | |
1318 | + mfb = AX_RX_CTL_MFB_4096; | |
1319 | + } else if (dev->hard_mtu < 8192) { | |
1320 | + dev->rx_urb_size = 8192; | |
1321 | + mfb = AX_RX_CTL_MFB_8192; | |
1322 | + } else if (dev->hard_mtu < 16384) { | |
1323 | + dev->rx_urb_size = 16384; | |
1324 | + mfb = AX_RX_CTL_MFB_16384; | |
1325 | + } | |
1326 | + | |
1327 | + rxctl = asix_read_rx_ctl(dev); | |
1328 | + asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); | |
1329 | + | |
1330 | + medium = asix_read_medium_status(dev); | |
1331 | + if (dev->net->mtu > 1500) | |
1332 | + medium |= AX_MEDIUM_JFE; | |
1333 | + else | |
1334 | + medium &= ~AX_MEDIUM_JFE; | |
1335 | + asix_write_medium_mode(dev, medium); | |
1336 | + | |
1337 | + if (dev->rx_urb_size > old_rx_urb_size) | |
1338 | + usbnet_unlink_rx_urbs(dev); | |
1339 | +} | |
1340 | + | |
1341 | +static int ax88178_change_mtu(struct net_device *net, int new_mtu) | |
1342 | +{ | |
1343 | + struct usbnet *dev = netdev_priv(net); | |
1344 | + int ll_mtu = new_mtu + net->hard_header_len + 4; | |
1345 | + | |
1346 | + netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); | |
1347 | + | |
1348 | + if (new_mtu <= 0 || ll_mtu > 16384) | |
1349 | + return -EINVAL; | |
1350 | + | |
1351 | + if ((ll_mtu % dev->maxpacket) == 0) | |
1352 | + return -EDOM; | |
1353 | + | |
1354 | + net->mtu = new_mtu; | |
1355 | + dev->hard_mtu = net->mtu + net->hard_header_len; | |
1356 | + ax88178_set_mfb(dev); | |
1357 | + | |
1358 | + /* max qlen depend on hard_mtu and rx_urb_size */ | |
1359 | + usbnet_update_max_qlen(dev); | |
1360 | + | |
1361 | + return 0; | |
1362 | +} | |
1363 | + | |
1364 | +static const struct net_device_ops ax88178_netdev_ops = { | |
1365 | + .ndo_open = usbnet_open, | |
1366 | + .ndo_stop = usbnet_stop, | |
1367 | + .ndo_start_xmit = usbnet_start_xmit, | |
1368 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
1369 | + .ndo_set_mac_address = asix_set_mac_address, | |
1370 | + .ndo_validate_addr = eth_validate_addr, | |
1371 | + .ndo_set_rx_mode = asix_set_multicast, | |
1372 | + .ndo_do_ioctl = asix_ioctl, | |
1373 | + .ndo_change_mtu = ax88178_change_mtu, | |
1374 | +}; | |
1375 | + | |
1376 | +static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) | |
1377 | +{ | |
1378 | + int ret; | |
1379 | + u8 buf[ETH_ALEN]; | |
1380 | + | |
1381 | + usbnet_get_endpoints(dev,intf); | |
1382 | + | |
1383 | + /* Get the MAC address */ | |
1384 | + ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | |
1385 | + if (ret < 0) { | |
1386 | + netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); | |
1387 | + return ret; | |
1388 | + } | |
1389 | + | |
1390 | + asix_set_netdev_dev_addr(dev, buf); | |
1391 | + | |
1392 | + /* Initialize MII structure */ | |
1393 | + dev->mii.dev = dev->net; | |
1394 | + dev->mii.mdio_read = asix_mdio_read; | |
1395 | + dev->mii.mdio_write = asix_mdio_write; | |
1396 | + dev->mii.phy_id_mask = 0x1f; | |
1397 | + dev->mii.reg_num_mask = 0xff; | |
1398 | + dev->mii.supports_gmii = 1; | |
1399 | + dev->mii.phy_id = asix_get_phy_addr(dev); | |
1400 | + | |
1401 | + dev->net->netdev_ops = &ax88178_netdev_ops; | |
1402 | + dev->net->ethtool_ops = &ax88178_ethtool_ops; | |
1403 | + | |
1404 | + /* Blink LEDS so users know driver saw dongle */ | |
1405 | + asix_sw_reset(dev, 0); | |
1406 | + msleep(150); | |
1407 | + | |
1408 | + asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); | |
1409 | + msleep(150); | |
1410 | + | |
1411 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | |
1412 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { | |
1413 | + /* hard_mtu is still the default - the device does not support | |
1414 | + jumbo eth frames */ | |
1415 | + dev->rx_urb_size = 2048; | |
1416 | + } | |
1417 | + | |
1418 | + dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); | |
1419 | + if (!dev->driver_priv) | |
1420 | + return -ENOMEM; | |
1421 | + | |
1422 | + return 0; | |
1423 | +} | |
1424 | + | |
1425 | +static const struct driver_info ax8817x_info = { | |
1426 | + .description = "ASIX AX8817x USB 2.0 Ethernet", | |
1427 | + .bind = ax88172_bind, | |
1428 | + .status = asix_status, | |
1429 | + .link_reset = ax88172_link_reset, | |
1430 | + .reset = ax88172_link_reset, | |
1431 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
1432 | + .data = 0x00130103, | |
1433 | +}; | |
1434 | + | |
1435 | +static const struct driver_info dlink_dub_e100_info = { | |
1436 | + .description = "DLink DUB-E100 USB Ethernet", | |
1437 | + .bind = ax88172_bind, | |
1438 | + .status = asix_status, | |
1439 | + .link_reset = ax88172_link_reset, | |
1440 | + .reset = ax88172_link_reset, | |
1441 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
1442 | + .data = 0x009f9d9f, | |
1443 | +}; | |
1444 | + | |
1445 | +static const struct driver_info netgear_fa120_info = { | |
1446 | + .description = "Netgear FA-120 USB Ethernet", | |
1447 | + .bind = ax88172_bind, | |
1448 | + .status = asix_status, | |
1449 | + .link_reset = ax88172_link_reset, | |
1450 | + .reset = ax88172_link_reset, | |
1451 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
1452 | + .data = 0x00130103, | |
1453 | +}; | |
1454 | + | |
1455 | +static const struct driver_info hawking_uf200_info = { | |
1456 | + .description = "Hawking UF200 USB Ethernet", | |
1457 | + .bind = ax88172_bind, | |
1458 | + .status = asix_status, | |
1459 | + .link_reset = ax88172_link_reset, | |
1460 | + .reset = ax88172_link_reset, | |
1461 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
1462 | + .data = 0x001f1d1f, | |
1463 | +}; | |
1464 | + | |
1465 | +static const struct driver_info ax88772_info = { | |
1466 | + .description = "ASIX AX88772 USB 2.0 Ethernet", | |
1467 | + .bind = ax88772_bind, | |
1468 | + .unbind = ax88772_unbind, | |
1469 | + .status = asix_status, | |
1470 | + .link_reset = ax88772_link_reset, | |
1471 | + .reset = ax88772_link_reset, | |
1472 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, | |
1473 | + .rx_fixup = asix_rx_fixup_common, | |
1474 | + .tx_fixup = asix_tx_fixup, | |
1475 | +}; | |
1476 | + | |
1477 | +static const struct driver_info ax88772b_info = { | |
1478 | + .description = "ASIX AX88772B USB 2.0 Ethernet", | |
1479 | + .bind = ax88772_bind, | |
1480 | + .unbind = ax88772_unbind, | |
1481 | + .status = asix_status, | |
1482 | + .link_reset = ax88772_link_reset, | |
1483 | + .reset = ax88772_reset, | |
1484 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | |
1485 | + FLAG_MULTI_PACKET, | |
1486 | + .rx_fixup = asix_rx_fixup_common, | |
1487 | + .tx_fixup = asix_tx_fixup, | |
1488 | + .data = FLAG_EEPROM_MAC, | |
1489 | +}; | |
1490 | + | |
1491 | +static const struct driver_info ax88178_info = { | |
1492 | + .description = "ASIX AX88178 USB 2.0 Ethernet", | |
1493 | + .bind = ax88178_bind, | |
1494 | + .unbind = ax88772_unbind, | |
1495 | + .status = asix_status, | |
1496 | + .link_reset = ax88178_link_reset, | |
1497 | + .reset = ax88178_reset, | |
1498 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | |
1499 | + FLAG_MULTI_PACKET, | |
1500 | + .rx_fixup = asix_rx_fixup_common, | |
1501 | + .tx_fixup = asix_tx_fixup, | |
1502 | +}; | |
1503 | + | |
1504 | +/* | |
1505 | + * USBLINK 20F9 "USB 2.0 LAN" USB ethernet adapter, typically found in | |
1506 | + * no-name packaging. | |
1507 | + * USB device strings are: | |
1508 | + * 1: Manufacturer: USBLINK | |
1509 | + * 2: Product: HG20F9 USB2.0 | |
1510 | + * 3: Serial: 000003 | |
1511 | + * Appears to be compatible with Asix 88772B. | |
1512 | + */ | |
1513 | +static const struct driver_info hg20f9_info = { | |
1514 | + .description = "HG20F9 USB 2.0 Ethernet", | |
1515 | + .bind = ax88772_bind, | |
1516 | + .unbind = ax88772_unbind, | |
1517 | + .status = asix_status, | |
1518 | + .link_reset = ax88772_link_reset, | |
1519 | + .reset = ax88772_reset, | |
1520 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | |
1521 | + FLAG_MULTI_PACKET, | |
1522 | + .rx_fixup = asix_rx_fixup_common, | |
1523 | + .tx_fixup = asix_tx_fixup, | |
1524 | + .data = FLAG_EEPROM_MAC, | |
1525 | +}; | |
1526 | + | |
1527 | +static const struct usb_device_id products [] = { | |
1528 | +{ | |
1529 | + // Linksys USB200M | |
1530 | + USB_DEVICE (0x077b, 0x2226), | |
1531 | + .driver_info = (unsigned long) &ax8817x_info, | |
1532 | +}, { | |
1533 | + // Netgear FA120 | |
1534 | + USB_DEVICE (0x0846, 0x1040), | |
1535 | + .driver_info = (unsigned long) &netgear_fa120_info, | |
1536 | +}, { | |
1537 | + // DLink DUB-E100 | |
1538 | + USB_DEVICE (0x2001, 0x1a00), | |
1539 | + .driver_info = (unsigned long) &dlink_dub_e100_info, | |
1540 | +}, { | |
1541 | + // Intellinet, ST Lab USB Ethernet | |
1542 | + USB_DEVICE (0x0b95, 0x1720), | |
1543 | + .driver_info = (unsigned long) &ax8817x_info, | |
1544 | +}, { | |
1545 | + // Hawking UF200, TrendNet TU2-ET100 | |
1546 | + USB_DEVICE (0x07b8, 0x420a), | |
1547 | + .driver_info = (unsigned long) &hawking_uf200_info, | |
1548 | +}, { | |
1549 | + // Billionton Systems, USB2AR | |
1550 | + USB_DEVICE (0x08dd, 0x90ff), | |
1551 | + .driver_info = (unsigned long) &ax8817x_info, | |
1552 | +}, { | |
1553 | + // ATEN UC210T | |
1554 | + USB_DEVICE (0x0557, 0x2009), | |
1555 | + .driver_info = (unsigned long) &ax8817x_info, | |
1556 | +}, { | |
1557 | + // Buffalo LUA-U2-KTX | |
1558 | + USB_DEVICE (0x0411, 0x003d), | |
1559 | + .driver_info = (unsigned long) &ax8817x_info, | |
1560 | +}, { | |
1561 | + // Buffalo LUA-U2-GT 10/100/1000 | |
1562 | + USB_DEVICE (0x0411, 0x006e), | |
1563 | + .driver_info = (unsigned long) &ax88178_info, | |
1564 | +}, { | |
1565 | + // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" | |
1566 | + USB_DEVICE (0x6189, 0x182d), | |
1567 | + .driver_info = (unsigned long) &ax8817x_info, | |
1568 | +}, { | |
1569 | + // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" | |
1570 | + USB_DEVICE (0x0df6, 0x0056), | |
1571 | + .driver_info = (unsigned long) &ax88178_info, | |
1572 | +}, { | |
1573 | + // corega FEther USB2-TX | |
1574 | + USB_DEVICE (0x07aa, 0x0017), | |
1575 | + .driver_info = (unsigned long) &ax8817x_info, | |
1576 | +}, { | |
1577 | + // Surecom EP-1427X-2 | |
1578 | + USB_DEVICE (0x1189, 0x0893), | |
1579 | + .driver_info = (unsigned long) &ax8817x_info, | |
1580 | +}, { | |
1581 | + // goodway corp usb gwusb2e | |
1582 | + USB_DEVICE (0x1631, 0x6200), | |
1583 | + .driver_info = (unsigned long) &ax8817x_info, | |
1584 | +}, { | |
1585 | + // JVC MP-PRX1 Port Replicator | |
1586 | + USB_DEVICE (0x04f1, 0x3008), | |
1587 | + .driver_info = (unsigned long) &ax8817x_info, | |
1588 | +}, { | |
1589 | + // Lenovo U2L100P 10/100 | |
1590 | + USB_DEVICE (0x17ef, 0x7203), | |
1591 | + .driver_info = (unsigned long) &ax88772_info, | |
1592 | +}, { | |
1593 | + // ASIX AX88772B 10/100 | |
1594 | + USB_DEVICE (0x0b95, 0x772b), | |
1595 | + .driver_info = (unsigned long) &ax88772b_info, | |
1596 | +}, { | |
1597 | + // ASIX AX88772 10/100 | |
1598 | + USB_DEVICE (0x0b95, 0x7720), | |
1599 | + .driver_info = (unsigned long) &ax88772_info, | |
1600 | +}, { | |
1601 | + // ASIX AX88178 10/100/1000 | |
1602 | + USB_DEVICE (0x0b95, 0x1780), | |
1603 | + .driver_info = (unsigned long) &ax88178_info, | |
1604 | +}, { | |
1605 | + // Logitec LAN-GTJ/U2A | |
1606 | + USB_DEVICE (0x0789, 0x0160), | |
1607 | + .driver_info = (unsigned long) &ax88178_info, | |
1608 | +}, { | |
1609 | + // Linksys USB200M Rev 2 | |
1610 | + USB_DEVICE (0x13b1, 0x0018), | |
1611 | + .driver_info = (unsigned long) &ax88772_info, | |
1612 | +}, { | |
1613 | + // 0Q0 cable ethernet | |
1614 | + USB_DEVICE (0x1557, 0x7720), | |
1615 | + .driver_info = (unsigned long) &ax88772_info, | |
1616 | +}, { | |
1617 | + // DLink DUB-E100 H/W Ver B1 | |
1618 | + USB_DEVICE (0x07d1, 0x3c05), | |
1619 | + .driver_info = (unsigned long) &ax88772_info, | |
1620 | +}, { | |
1621 | + // DLink DUB-E100 H/W Ver B1 Alternate | |
1622 | + USB_DEVICE (0x2001, 0x3c05), | |
1623 | + .driver_info = (unsigned long) &ax88772_info, | |
1624 | +}, { | |
1625 | + // DLink DUB-E100 H/W Ver C1 | |
1626 | + USB_DEVICE (0x2001, 0x1a02), | |
1627 | + .driver_info = (unsigned long) &ax88772_info, | |
1628 | +}, { | |
1629 | + // Linksys USB1000 | |
1630 | + USB_DEVICE (0x1737, 0x0039), | |
1631 | + .driver_info = (unsigned long) &ax88178_info, | |
1632 | +}, { | |
1633 | + // IO-DATA ETG-US2 | |
1634 | + USB_DEVICE (0x04bb, 0x0930), | |
1635 | + .driver_info = (unsigned long) &ax88178_info, | |
1636 | +}, { | |
1637 | + // Belkin F5D5055 | |
1638 | + USB_DEVICE(0x050d, 0x5055), | |
1639 | + .driver_info = (unsigned long) &ax88178_info, | |
1640 | +}, { | |
1641 | + // Apple USB Ethernet Adapter | |
1642 | + USB_DEVICE(0x05ac, 0x1402), | |
1643 | + .driver_info = (unsigned long) &ax88772_info, | |
1644 | +}, { | |
1645 | + // Cables-to-Go USB Ethernet Adapter | |
1646 | + USB_DEVICE(0x0b95, 0x772a), | |
1647 | + .driver_info = (unsigned long) &ax88772_info, | |
1648 | +}, { | |
1649 | + // ABOCOM for pci | |
1650 | + USB_DEVICE(0x14ea, 0xab11), | |
1651 | + .driver_info = (unsigned long) &ax88178_info, | |
1652 | +}, { | |
1653 | + // ASIX 88772a | |
1654 | + USB_DEVICE(0x0db0, 0xa877), | |
1655 | + .driver_info = (unsigned long) &ax88772_info, | |
1656 | +}, { | |
1657 | + // Asus USB Ethernet Adapter | |
1658 | + USB_DEVICE (0x0b95, 0x7e2b), | |
1659 | + .driver_info = (unsigned long) &ax88772_info, | |
1660 | +}, { | |
1661 | + /* ASIX 88172a demo board */ | |
1662 | + USB_DEVICE(0x0b95, 0x172a), | |
1663 | + .driver_info = (unsigned long) &ax88172a_info, | |
1664 | +}, { | |
1665 | + /* | |
1666 | + * USBLINK HG20F9 "USB 2.0 LAN" | |
1667 | + * Appears to have gazumped Linksys's manufacturer ID but | |
1668 | + * doesn't (yet) conflict with any known Linksys product. | |
1669 | + */ | |
1670 | + USB_DEVICE(0x066b, 0x20f9), | |
1671 | + .driver_info = (unsigned long) &hg20f9_info, | |
1672 | +}, | |
1673 | + { }, // END | |
1674 | +}; | |
1675 | +MODULE_DEVICE_TABLE(usb, products); | |
1676 | + | |
1677 | +static struct usb_driver asix_driver = { | |
1678 | + .name = DRIVER_NAME, | |
1679 | + .id_table = products, | |
1680 | + .probe = usbnet_probe, | |
1681 | + .suspend = usbnet_suspend, | |
1682 | + .resume = usbnet_resume, | |
1683 | + .disconnect = usbnet_disconnect, | |
1684 | + .supports_autosuspend = 1, | |
1685 | + .disable_hub_initiated_lpm = 1, | |
1686 | +}; | |
1687 | + | |
1688 | +module_usb_driver(asix_driver); | |
1689 | + | |
1690 | +MODULE_AUTHOR("David Hollis"); | |
1691 | +MODULE_VERSION(DRIVER_VERSION); | |
1692 | +MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); | |
1693 | +MODULE_LICENSE("GPL"); | |
1694 | + | |
1695 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/asix.h backports-3.18.1-1/drivers/net/usb/asix.h | |
1696 | --- backports-3.18.1-1.org/drivers/net/usb/asix.h 1970-01-01 01:00:00.000000000 +0100 | |
1697 | +++ backports-3.18.1-1/drivers/net/usb/asix.h 2014-12-16 18:39:45.000000000 +0100 | |
1698 | @@ -0,0 +1,234 @@ | |
1699 | +/* | |
1700 | + * ASIX AX8817X based USB 2.0 Ethernet Devices | |
1701 | + * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | |
1702 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | |
1703 | + * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | |
1704 | + * Copyright (c) 2002-2003 TiVo Inc. | |
1705 | + * | |
1706 | + * This program is free software; you can redistribute it and/or modify | |
1707 | + * it under the terms of the GNU General Public License as published by | |
1708 | + * the Free Software Foundation; either version 2 of the License, or | |
1709 | + * (at your option) any later version. | |
1710 | + * | |
1711 | + * This program is distributed in the hope that it will be useful, | |
1712 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1713 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1714 | + * GNU General Public License for more details. | |
1715 | + * | |
1716 | + * You should have received a copy of the GNU General Public License | |
1717 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
1718 | + */ | |
1719 | + | |
1720 | +#ifndef _ASIX_H | |
1721 | +#define _ASIX_H | |
1722 | + | |
1723 | +// #define DEBUG // error path messages, extra info | |
1724 | +// #define VERBOSE // more; success messages | |
1725 | + | |
1726 | +#include <linux/module.h> | |
1727 | +#include <linux/kmod.h> | |
1728 | +#include <linux/netdevice.h> | |
1729 | +#include <linux/etherdevice.h> | |
1730 | +#include <linux/ethtool.h> | |
1731 | +#include <linux/workqueue.h> | |
1732 | +#include <linux/mii.h> | |
1733 | +#include <linux/usb.h> | |
1734 | +#include <linux/crc32.h> | |
1735 | +#include <linux/usb/usbnet.h> | |
1736 | +#include <linux/slab.h> | |
1737 | +#include <linux/if_vlan.h> | |
1738 | + | |
1739 | +#define DRIVER_VERSION "22-Dec-2011" | |
1740 | +#define DRIVER_NAME "asix" | |
1741 | + | |
1742 | +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ | |
1743 | + | |
1744 | +#define AX_CMD_SET_SW_MII 0x06 | |
1745 | +#define AX_CMD_READ_MII_REG 0x07 | |
1746 | +#define AX_CMD_WRITE_MII_REG 0x08 | |
1747 | +#define AX_CMD_SET_HW_MII 0x0a | |
1748 | +#define AX_CMD_READ_EEPROM 0x0b | |
1749 | +#define AX_CMD_WRITE_EEPROM 0x0c | |
1750 | +#define AX_CMD_WRITE_ENABLE 0x0d | |
1751 | +#define AX_CMD_WRITE_DISABLE 0x0e | |
1752 | +#define AX_CMD_READ_RX_CTL 0x0f | |
1753 | +#define AX_CMD_WRITE_RX_CTL 0x10 | |
1754 | +#define AX_CMD_READ_IPG012 0x11 | |
1755 | +#define AX_CMD_WRITE_IPG0 0x12 | |
1756 | +#define AX_CMD_WRITE_IPG1 0x13 | |
1757 | +#define AX_CMD_READ_NODE_ID 0x13 | |
1758 | +#define AX_CMD_WRITE_NODE_ID 0x14 | |
1759 | +#define AX_CMD_WRITE_IPG2 0x14 | |
1760 | +#define AX_CMD_WRITE_MULTI_FILTER 0x16 | |
1761 | +#define AX88172_CMD_READ_NODE_ID 0x17 | |
1762 | +#define AX_CMD_READ_PHY_ID 0x19 | |
1763 | +#define AX_CMD_READ_MEDIUM_STATUS 0x1a | |
1764 | +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b | |
1765 | +#define AX_CMD_READ_MONITOR_MODE 0x1c | |
1766 | +#define AX_CMD_WRITE_MONITOR_MODE 0x1d | |
1767 | +#define AX_CMD_READ_GPIOS 0x1e | |
1768 | +#define AX_CMD_WRITE_GPIOS 0x1f | |
1769 | +#define AX_CMD_SW_RESET 0x20 | |
1770 | +#define AX_CMD_SW_PHY_STATUS 0x21 | |
1771 | +#define AX_CMD_SW_PHY_SELECT 0x22 | |
1772 | + | |
1773 | +#define AX_PHY_SELECT_MASK (BIT(3) | BIT(2)) | |
1774 | +#define AX_PHY_SELECT_INTERNAL 0 | |
1775 | +#define AX_PHY_SELECT_EXTERNAL BIT(2) | |
1776 | + | |
1777 | +#define AX_MONITOR_MODE 0x01 | |
1778 | +#define AX_MONITOR_LINK 0x02 | |
1779 | +#define AX_MONITOR_MAGIC 0x04 | |
1780 | +#define AX_MONITOR_HSFS 0x10 | |
1781 | + | |
1782 | +/* AX88172 Medium Status Register values */ | |
1783 | +#define AX88172_MEDIUM_FD 0x02 | |
1784 | +#define AX88172_MEDIUM_TX 0x04 | |
1785 | +#define AX88172_MEDIUM_FC 0x10 | |
1786 | +#define AX88172_MEDIUM_DEFAULT \ | |
1787 | + ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) | |
1788 | + | |
1789 | +#define AX_MCAST_FILTER_SIZE 8 | |
1790 | +#define AX_MAX_MCAST 64 | |
1791 | + | |
1792 | +#define AX_SWRESET_CLEAR 0x00 | |
1793 | +#define AX_SWRESET_RR 0x01 | |
1794 | +#define AX_SWRESET_RT 0x02 | |
1795 | +#define AX_SWRESET_PRTE 0x04 | |
1796 | +#define AX_SWRESET_PRL 0x08 | |
1797 | +#define AX_SWRESET_BZ 0x10 | |
1798 | +#define AX_SWRESET_IPRL 0x20 | |
1799 | +#define AX_SWRESET_IPPD 0x40 | |
1800 | + | |
1801 | +#define AX88772_IPG0_DEFAULT 0x15 | |
1802 | +#define AX88772_IPG1_DEFAULT 0x0c | |
1803 | +#define AX88772_IPG2_DEFAULT 0x12 | |
1804 | + | |
1805 | +/* AX88772 & AX88178 Medium Mode Register */ | |
1806 | +#define AX_MEDIUM_PF 0x0080 | |
1807 | +#define AX_MEDIUM_JFE 0x0040 | |
1808 | +#define AX_MEDIUM_TFC 0x0020 | |
1809 | +#define AX_MEDIUM_RFC 0x0010 | |
1810 | +#define AX_MEDIUM_ENCK 0x0008 | |
1811 | +#define AX_MEDIUM_AC 0x0004 | |
1812 | +#define AX_MEDIUM_FD 0x0002 | |
1813 | +#define AX_MEDIUM_GM 0x0001 | |
1814 | +#define AX_MEDIUM_SM 0x1000 | |
1815 | +#define AX_MEDIUM_SBP 0x0800 | |
1816 | +#define AX_MEDIUM_PS 0x0200 | |
1817 | +#define AX_MEDIUM_RE 0x0100 | |
1818 | + | |
1819 | +#define AX88178_MEDIUM_DEFAULT \ | |
1820 | + (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ | |
1821 | + AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ | |
1822 | + AX_MEDIUM_RE) | |
1823 | + | |
1824 | +#define AX88772_MEDIUM_DEFAULT \ | |
1825 | + (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ | |
1826 | + AX_MEDIUM_TFC | AX_MEDIUM_PS | \ | |
1827 | + AX_MEDIUM_AC | AX_MEDIUM_RE) | |
1828 | + | |
1829 | +/* AX88772 & AX88178 RX_CTL values */ | |
1830 | +#define AX_RX_CTL_SO 0x0080 | |
1831 | +#define AX_RX_CTL_AP 0x0020 | |
1832 | +#define AX_RX_CTL_AM 0x0010 | |
1833 | +#define AX_RX_CTL_AB 0x0008 | |
1834 | +#define AX_RX_CTL_SEP 0x0004 | |
1835 | +#define AX_RX_CTL_AMALL 0x0002 | |
1836 | +#define AX_RX_CTL_PRO 0x0001 | |
1837 | +#define AX_RX_CTL_MFB_2048 0x0000 | |
1838 | +#define AX_RX_CTL_MFB_4096 0x0100 | |
1839 | +#define AX_RX_CTL_MFB_8192 0x0200 | |
1840 | +#define AX_RX_CTL_MFB_16384 0x0300 | |
1841 | + | |
1842 | +#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) | |
1843 | + | |
1844 | +/* GPIO 0 .. 2 toggles */ | |
1845 | +#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ | |
1846 | +#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ | |
1847 | +#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ | |
1848 | +#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ | |
1849 | +#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ | |
1850 | +#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ | |
1851 | +#define AX_GPIO_RESERVED 0x40 /* Reserved */ | |
1852 | +#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ | |
1853 | + | |
1854 | +#define AX_EEPROM_MAGIC 0xdeadbeef | |
1855 | +#define AX_EEPROM_LEN 0x200 | |
1856 | + | |
1857 | +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | |
1858 | +struct asix_data { | |
1859 | + u8 multi_filter[AX_MCAST_FILTER_SIZE]; | |
1860 | + u8 mac_addr[ETH_ALEN]; | |
1861 | + u8 phymode; | |
1862 | + u8 ledmode; | |
1863 | + u8 res; | |
1864 | +}; | |
1865 | + | |
1866 | +struct asix_rx_fixup_info { | |
1867 | + struct sk_buff *ax_skb; | |
1868 | + u32 header; | |
1869 | + u16 size; | |
1870 | + bool split_head; | |
1871 | +}; | |
1872 | + | |
1873 | +struct asix_common_private { | |
1874 | + struct asix_rx_fixup_info rx_fixup_info; | |
1875 | +}; | |
1876 | + | |
1877 | +extern const struct driver_info ax88172a_info; | |
1878 | + | |
1879 | +/* ASIX specific flags */ | |
1880 | +#define FLAG_EEPROM_MAC (1UL << 0) /* init device MAC from eeprom */ | |
1881 | + | |
1882 | +int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
1883 | + u16 size, void *data); | |
1884 | + | |
1885 | +int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
1886 | + u16 size, void *data); | |
1887 | + | |
1888 | +void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, | |
1889 | + u16 index, u16 size, void *data); | |
1890 | + | |
1891 | +int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, | |
1892 | + struct asix_rx_fixup_info *rx); | |
1893 | +int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb); | |
1894 | + | |
1895 | +struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
1896 | + gfp_t flags); | |
1897 | + | |
1898 | +int asix_set_sw_mii(struct usbnet *dev); | |
1899 | +int asix_set_hw_mii(struct usbnet *dev); | |
1900 | + | |
1901 | +int asix_read_phy_addr(struct usbnet *dev, int internal); | |
1902 | +int asix_get_phy_addr(struct usbnet *dev); | |
1903 | + | |
1904 | +int asix_sw_reset(struct usbnet *dev, u8 flags); | |
1905 | + | |
1906 | +u16 asix_read_rx_ctl(struct usbnet *dev); | |
1907 | +int asix_write_rx_ctl(struct usbnet *dev, u16 mode); | |
1908 | + | |
1909 | +u16 asix_read_medium_status(struct usbnet *dev); | |
1910 | +int asix_write_medium_mode(struct usbnet *dev, u16 mode); | |
1911 | + | |
1912 | +int asix_write_gpio(struct usbnet *dev, u16 value, int sleep); | |
1913 | + | |
1914 | +void asix_set_multicast(struct net_device *net); | |
1915 | + | |
1916 | +int asix_mdio_read(struct net_device *netdev, int phy_id, int loc); | |
1917 | +void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val); | |
1918 | + | |
1919 | +void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); | |
1920 | +int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); | |
1921 | + | |
1922 | +int asix_get_eeprom_len(struct net_device *net); | |
1923 | +int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |
1924 | + u8 *data); | |
1925 | +int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |
1926 | + u8 *data); | |
1927 | + | |
1928 | +void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); | |
1929 | + | |
1930 | +int asix_set_mac_address(struct net_device *net, void *p); | |
1931 | + | |
1932 | +#endif /* _ASIX_H */ | |
1933 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/ax88172a.c backports-3.18.1-1/drivers/net/usb/ax88172a.c | |
1934 | --- backports-3.18.1-1.org/drivers/net/usb/ax88172a.c 1970-01-01 01:00:00.000000000 +0100 | |
1935 | +++ backports-3.18.1-1/drivers/net/usb/ax88172a.c 2014-12-16 18:39:45.000000000 +0100 | |
1936 | @@ -0,0 +1,422 @@ | |
1937 | +/* | |
1938 | + * ASIX AX88172A based USB 2.0 Ethernet Devices | |
1939 | + * Copyright (C) 2012 OMICRON electronics GmbH | |
1940 | + * | |
1941 | + * Supports external PHYs via phylib. Based on the driver for the | |
1942 | + * AX88772. Original copyrights follow: | |
1943 | + * | |
1944 | + * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> | |
1945 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | |
1946 | + * Copyright (C) 2006 James Painter <jamie.painter@iname.com> | |
1947 | + * Copyright (c) 2002-2003 TiVo Inc. | |
1948 | + * | |
1949 | + * This program is free software; you can redistribute it and/or modify | |
1950 | + * it under the terms of the GNU General Public License as published by | |
1951 | + * the Free Software Foundation; either version 2 of the License, or | |
1952 | + * (at your option) any later version. | |
1953 | + * | |
1954 | + * This program is distributed in the hope that it will be useful, | |
1955 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1956 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1957 | + * GNU General Public License for more details. | |
1958 | + * | |
1959 | + * You should have received a copy of the GNU General Public License | |
1960 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
1961 | + */ | |
1962 | + | |
1963 | +#include "asix.h" | |
1964 | +#include <linux/phy.h> | |
1965 | + | |
1966 | +struct ax88172a_private { | |
1967 | + struct mii_bus *mdio; | |
1968 | + struct phy_device *phydev; | |
1969 | + char phy_name[20]; | |
1970 | + u16 phy_addr; | |
1971 | + u16 oldmode; | |
1972 | + int use_embdphy; | |
1973 | + struct asix_rx_fixup_info rx_fixup_info; | |
1974 | +}; | |
1975 | + | |
1976 | +/* MDIO read and write wrappers for phylib */ | |
1977 | +static int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum) | |
1978 | +{ | |
1979 | + return asix_mdio_read(((struct usbnet *)bus->priv)->net, phy_id, | |
1980 | + regnum); | |
1981 | +} | |
1982 | + | |
1983 | +static int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, | |
1984 | + u16 val) | |
1985 | +{ | |
1986 | + asix_mdio_write(((struct usbnet *)bus->priv)->net, phy_id, regnum, val); | |
1987 | + return 0; | |
1988 | +} | |
1989 | + | |
1990 | +static int ax88172a_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
1991 | +{ | |
1992 | + if (!netif_running(net)) | |
1993 | + return -EINVAL; | |
1994 | + | |
1995 | + if (!net->phydev) | |
1996 | + return -ENODEV; | |
1997 | + | |
1998 | + return phy_mii_ioctl(net->phydev, rq, cmd); | |
1999 | +} | |
2000 | + | |
2001 | +/* set MAC link settings according to information from phylib */ | |
2002 | +static void ax88172a_adjust_link(struct net_device *netdev) | |
2003 | +{ | |
2004 | + struct phy_device *phydev = netdev->phydev; | |
2005 | + struct usbnet *dev = netdev_priv(netdev); | |
2006 | + struct ax88172a_private *priv = dev->driver_priv; | |
2007 | + u16 mode = 0; | |
2008 | + | |
2009 | + if (phydev->link) { | |
2010 | + mode = AX88772_MEDIUM_DEFAULT; | |
2011 | + | |
2012 | + if (phydev->duplex == DUPLEX_HALF) | |
2013 | + mode &= ~AX_MEDIUM_FD; | |
2014 | + | |
2015 | + if (phydev->speed != SPEED_100) | |
2016 | + mode &= ~AX_MEDIUM_PS; | |
2017 | + } | |
2018 | + | |
2019 | + if (mode != priv->oldmode) { | |
2020 | + asix_write_medium_mode(dev, mode); | |
2021 | + priv->oldmode = mode; | |
2022 | + netdev_dbg(netdev, "speed %u duplex %d, setting mode to 0x%04x\n", | |
2023 | + phydev->speed, phydev->duplex, mode); | |
2024 | + phy_print_status(phydev); | |
2025 | + } | |
2026 | +} | |
2027 | + | |
2028 | +static void ax88172a_status(struct usbnet *dev, struct urb *urb) | |
2029 | +{ | |
2030 | + /* link changes are detected by polling the phy */ | |
2031 | +} | |
2032 | + | |
2033 | +/* use phylib infrastructure */ | |
2034 | +static int ax88172a_init_mdio(struct usbnet *dev) | |
2035 | +{ | |
2036 | + struct ax88172a_private *priv = dev->driver_priv; | |
2037 | + int ret, i; | |
2038 | + | |
2039 | + priv->mdio = mdiobus_alloc(); | |
2040 | + if (!priv->mdio) { | |
2041 | + netdev_err(dev->net, "Could not allocate MDIO bus\n"); | |
2042 | + return -ENOMEM; | |
2043 | + } | |
2044 | + | |
2045 | + priv->mdio->priv = (void *)dev; | |
2046 | + priv->mdio->read = &asix_mdio_bus_read; | |
2047 | + priv->mdio->write = &asix_mdio_bus_write; | |
2048 | + priv->mdio->name = "Asix MDIO Bus"; | |
2049 | + /* mii bus name is usb-<usb bus number>-<usb device number> */ | |
2050 | + snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", | |
2051 | + dev->udev->bus->busnum, dev->udev->devnum); | |
2052 | + | |
2053 | + priv->mdio->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | |
2054 | + if (!priv->mdio->irq) { | |
2055 | + ret = -ENOMEM; | |
2056 | + goto mfree; | |
2057 | + } | |
2058 | + for (i = 0; i < PHY_MAX_ADDR; i++) | |
2059 | + priv->mdio->irq[i] = PHY_POLL; | |
2060 | + | |
2061 | + ret = mdiobus_register(priv->mdio); | |
2062 | + if (ret) { | |
2063 | + netdev_err(dev->net, "Could not register MDIO bus\n"); | |
2064 | + goto ifree; | |
2065 | + } | |
2066 | + | |
2067 | + netdev_info(dev->net, "registered mdio bus %s\n", priv->mdio->id); | |
2068 | + return 0; | |
2069 | + | |
2070 | +ifree: | |
2071 | + kfree(priv->mdio->irq); | |
2072 | +mfree: | |
2073 | + mdiobus_free(priv->mdio); | |
2074 | + return ret; | |
2075 | +} | |
2076 | + | |
2077 | +static void ax88172a_remove_mdio(struct usbnet *dev) | |
2078 | +{ | |
2079 | + struct ax88172a_private *priv = dev->driver_priv; | |
2080 | + | |
2081 | + netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id); | |
2082 | + mdiobus_unregister(priv->mdio); | |
2083 | + kfree(priv->mdio->irq); | |
2084 | + mdiobus_free(priv->mdio); | |
2085 | +} | |
2086 | + | |
2087 | +static const struct net_device_ops ax88172a_netdev_ops = { | |
2088 | + .ndo_open = usbnet_open, | |
2089 | + .ndo_stop = usbnet_stop, | |
2090 | + .ndo_start_xmit = usbnet_start_xmit, | |
2091 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
2092 | + .ndo_change_mtu = usbnet_change_mtu, | |
2093 | + .ndo_set_mac_address = asix_set_mac_address, | |
2094 | + .ndo_validate_addr = eth_validate_addr, | |
2095 | + .ndo_do_ioctl = ax88172a_ioctl, | |
2096 | + .ndo_set_rx_mode = asix_set_multicast, | |
2097 | +}; | |
2098 | + | |
2099 | +static int ax88172a_get_settings(struct net_device *net, | |
2100 | + struct ethtool_cmd *cmd) | |
2101 | +{ | |
2102 | + if (!net->phydev) | |
2103 | + return -ENODEV; | |
2104 | + | |
2105 | + return phy_ethtool_gset(net->phydev, cmd); | |
2106 | +} | |
2107 | + | |
2108 | +static int ax88172a_set_settings(struct net_device *net, | |
2109 | + struct ethtool_cmd *cmd) | |
2110 | +{ | |
2111 | + if (!net->phydev) | |
2112 | + return -ENODEV; | |
2113 | + | |
2114 | + return phy_ethtool_sset(net->phydev, cmd); | |
2115 | +} | |
2116 | + | |
2117 | +static int ax88172a_nway_reset(struct net_device *net) | |
2118 | +{ | |
2119 | + if (!net->phydev) | |
2120 | + return -ENODEV; | |
2121 | + | |
2122 | + return phy_start_aneg(net->phydev); | |
2123 | +} | |
2124 | + | |
2125 | +static const struct ethtool_ops ax88172a_ethtool_ops = { | |
2126 | + .get_drvinfo = asix_get_drvinfo, | |
2127 | + .get_link = usbnet_get_link, | |
2128 | + .get_msglevel = usbnet_get_msglevel, | |
2129 | + .set_msglevel = usbnet_set_msglevel, | |
2130 | + .get_wol = asix_get_wol, | |
2131 | + .set_wol = asix_set_wol, | |
2132 | + .get_eeprom_len = asix_get_eeprom_len, | |
2133 | + .get_eeprom = asix_get_eeprom, | |
2134 | + .set_eeprom = asix_set_eeprom, | |
2135 | + .get_settings = ax88172a_get_settings, | |
2136 | + .set_settings = ax88172a_set_settings, | |
2137 | + .nway_reset = ax88172a_nway_reset, | |
2138 | +}; | |
2139 | + | |
2140 | +static int ax88172a_reset_phy(struct usbnet *dev, int embd_phy) | |
2141 | +{ | |
2142 | + int ret; | |
2143 | + | |
2144 | + ret = asix_sw_reset(dev, AX_SWRESET_IPPD); | |
2145 | + if (ret < 0) | |
2146 | + goto err; | |
2147 | + | |
2148 | + msleep(150); | |
2149 | + ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); | |
2150 | + if (ret < 0) | |
2151 | + goto err; | |
2152 | + | |
2153 | + msleep(150); | |
2154 | + | |
2155 | + ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_IPPD); | |
2156 | + if (ret < 0) | |
2157 | + goto err; | |
2158 | + | |
2159 | + return 0; | |
2160 | + | |
2161 | +err: | |
2162 | + return ret; | |
2163 | +} | |
2164 | + | |
2165 | + | |
2166 | +static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) | |
2167 | +{ | |
2168 | + int ret; | |
2169 | + u8 buf[ETH_ALEN]; | |
2170 | + struct ax88172a_private *priv; | |
2171 | + | |
2172 | + usbnet_get_endpoints(dev, intf); | |
2173 | + | |
2174 | + priv = kzalloc(sizeof(*priv), GFP_KERNEL); | |
2175 | + if (!priv) | |
2176 | + return -ENOMEM; | |
2177 | + | |
2178 | + dev->driver_priv = priv; | |
2179 | + | |
2180 | + /* Get the MAC address */ | |
2181 | + ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); | |
2182 | + if (ret < 0) { | |
2183 | + netdev_err(dev->net, "Failed to read MAC address: %d\n", ret); | |
2184 | + goto free; | |
2185 | + } | |
2186 | + memcpy(dev->net->dev_addr, buf, ETH_ALEN); | |
2187 | + | |
2188 | + dev->net->netdev_ops = &ax88172a_netdev_ops; | |
2189 | + dev->net->ethtool_ops = &ax88172a_ethtool_ops; | |
2190 | + | |
2191 | + /* are we using the internal or the external phy? */ | |
2192 | + ret = asix_read_cmd(dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1, buf); | |
2193 | + if (ret < 0) { | |
2194 | + netdev_err(dev->net, "Failed to read software interface selection register: %d\n", | |
2195 | + ret); | |
2196 | + goto free; | |
2197 | + } | |
2198 | + | |
2199 | + netdev_dbg(dev->net, "AX_CMD_SW_PHY_STATUS = 0x%02x\n", buf[0]); | |
2200 | + switch (buf[0] & AX_PHY_SELECT_MASK) { | |
2201 | + case AX_PHY_SELECT_INTERNAL: | |
2202 | + netdev_dbg(dev->net, "use internal phy\n"); | |
2203 | + priv->use_embdphy = 1; | |
2204 | + break; | |
2205 | + case AX_PHY_SELECT_EXTERNAL: | |
2206 | + netdev_dbg(dev->net, "use external phy\n"); | |
2207 | + priv->use_embdphy = 0; | |
2208 | + break; | |
2209 | + default: | |
2210 | + netdev_err(dev->net, "Interface mode not supported by driver\n"); | |
2211 | + ret = -ENOTSUPP; | |
2212 | + goto free; | |
2213 | + } | |
2214 | + | |
2215 | + priv->phy_addr = asix_read_phy_addr(dev, priv->use_embdphy); | |
2216 | + ax88172a_reset_phy(dev, priv->use_embdphy); | |
2217 | + | |
2218 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ | |
2219 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { | |
2220 | + /* hard_mtu is still the default - the device does not support | |
2221 | + jumbo eth frames */ | |
2222 | + dev->rx_urb_size = 2048; | |
2223 | + } | |
2224 | + | |
2225 | + /* init MDIO bus */ | |
2226 | + ret = ax88172a_init_mdio(dev); | |
2227 | + if (ret) | |
2228 | + goto free; | |
2229 | + | |
2230 | + return 0; | |
2231 | + | |
2232 | +free: | |
2233 | + kfree(priv); | |
2234 | + return ret; | |
2235 | +} | |
2236 | + | |
2237 | +static int ax88172a_stop(struct usbnet *dev) | |
2238 | +{ | |
2239 | + struct ax88172a_private *priv = dev->driver_priv; | |
2240 | + | |
2241 | + netdev_dbg(dev->net, "Stopping interface\n"); | |
2242 | + | |
2243 | + if (priv->phydev) { | |
2244 | + netdev_info(dev->net, "Disconnecting from phy %s\n", | |
2245 | + priv->phy_name); | |
2246 | + phy_stop(priv->phydev); | |
2247 | + phy_disconnect(priv->phydev); | |
2248 | + } | |
2249 | + | |
2250 | + return 0; | |
2251 | +} | |
2252 | + | |
2253 | +static void ax88172a_unbind(struct usbnet *dev, struct usb_interface *intf) | |
2254 | +{ | |
2255 | + struct ax88172a_private *priv = dev->driver_priv; | |
2256 | + | |
2257 | + ax88172a_remove_mdio(dev); | |
2258 | + kfree(priv); | |
2259 | +} | |
2260 | + | |
2261 | +static int ax88172a_reset(struct usbnet *dev) | |
2262 | +{ | |
2263 | + struct asix_data *data = (struct asix_data *)&dev->data; | |
2264 | + struct ax88172a_private *priv = dev->driver_priv; | |
2265 | + int ret; | |
2266 | + u16 rx_ctl; | |
2267 | + | |
2268 | + ax88172a_reset_phy(dev, priv->use_embdphy); | |
2269 | + | |
2270 | + msleep(150); | |
2271 | + rx_ctl = asix_read_rx_ctl(dev); | |
2272 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | |
2273 | + ret = asix_write_rx_ctl(dev, 0x0000); | |
2274 | + if (ret < 0) | |
2275 | + goto out; | |
2276 | + | |
2277 | + rx_ctl = asix_read_rx_ctl(dev); | |
2278 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | |
2279 | + | |
2280 | + msleep(150); | |
2281 | + | |
2282 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, | |
2283 | + AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, | |
2284 | + AX88772_IPG2_DEFAULT, 0, NULL); | |
2285 | + if (ret < 0) { | |
2286 | + netdev_err(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); | |
2287 | + goto out; | |
2288 | + } | |
2289 | + | |
2290 | + /* Rewrite MAC address */ | |
2291 | + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | |
2292 | + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
2293 | + data->mac_addr); | |
2294 | + if (ret < 0) | |
2295 | + goto out; | |
2296 | + | |
2297 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | |
2298 | + ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); | |
2299 | + if (ret < 0) | |
2300 | + goto out; | |
2301 | + | |
2302 | + rx_ctl = asix_read_rx_ctl(dev); | |
2303 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", | |
2304 | + rx_ctl); | |
2305 | + | |
2306 | + rx_ctl = asix_read_medium_status(dev); | |
2307 | + netdev_dbg(dev->net, "Medium Status is 0x%04x after all initializations\n", | |
2308 | + rx_ctl); | |
2309 | + | |
2310 | + /* Connect to PHY */ | |
2311 | + snprintf(priv->phy_name, 20, PHY_ID_FMT, | |
2312 | + priv->mdio->id, priv->phy_addr); | |
2313 | + | |
2314 | + priv->phydev = phy_connect(dev->net, priv->phy_name, | |
2315 | + &ax88172a_adjust_link, | |
2316 | + PHY_INTERFACE_MODE_MII); | |
2317 | + if (IS_ERR(priv->phydev)) { | |
2318 | + netdev_err(dev->net, "Could not connect to PHY device %s\n", | |
2319 | + priv->phy_name); | |
2320 | + ret = PTR_ERR(priv->phydev); | |
2321 | + goto out; | |
2322 | + } | |
2323 | + | |
2324 | + netdev_info(dev->net, "Connected to phy %s\n", priv->phy_name); | |
2325 | + | |
2326 | + /* During power-up, the AX88172A set the power down (BMCR_PDOWN) | |
2327 | + * bit of the PHY. Bring the PHY up again. | |
2328 | + */ | |
2329 | + genphy_resume(priv->phydev); | |
2330 | + phy_start(priv->phydev); | |
2331 | + | |
2332 | + return 0; | |
2333 | + | |
2334 | +out: | |
2335 | + return ret; | |
2336 | + | |
2337 | +} | |
2338 | + | |
2339 | +static int ax88172a_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
2340 | +{ | |
2341 | + struct ax88172a_private *dp = dev->driver_priv; | |
2342 | + struct asix_rx_fixup_info *rx = &dp->rx_fixup_info; | |
2343 | + | |
2344 | + return asix_rx_fixup_internal(dev, skb, rx); | |
2345 | +} | |
2346 | + | |
2347 | +const struct driver_info ax88172a_info = { | |
2348 | + .description = "ASIX AX88172A USB 2.0 Ethernet", | |
2349 | + .bind = ax88172a_bind, | |
2350 | + .reset = ax88172a_reset, | |
2351 | + .stop = ax88172a_stop, | |
2352 | + .unbind = ax88172a_unbind, | |
2353 | + .status = ax88172a_status, | |
2354 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | | |
2355 | + FLAG_MULTI_PACKET, | |
2356 | + .rx_fixup = ax88172a_rx_fixup, | |
2357 | + .tx_fixup = asix_tx_fixup, | |
2358 | +}; | |
2359 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/ax88179_178a.c backports-3.18.1-1/drivers/net/usb/ax88179_178a.c | |
2360 | --- backports-3.18.1-1.org/drivers/net/usb/ax88179_178a.c 1970-01-01 01:00:00.000000000 +0100 | |
2361 | +++ backports-3.18.1-1/drivers/net/usb/ax88179_178a.c 2014-12-16 18:39:45.000000000 +0100 | |
2362 | @@ -0,0 +1,1756 @@ | |
2363 | +/* | |
2364 | + * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices | |
2365 | + * | |
2366 | + * Copyright (C) 2011-2013 ASIX | |
2367 | + * | |
2368 | + * This program is free software; you can redistribute it and/or modify | |
2369 | + * it under the terms of the GNU General Public License | |
2370 | + * as published by the Free Software Foundation; either version 2 | |
2371 | + * of the License, or (at your option) any later version. | |
2372 | + * | |
2373 | + * This program is distributed in the hope that it will be useful, | |
2374 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2375 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2376 | + * GNU General Public License for more details. | |
2377 | + * | |
2378 | + * You should have received a copy of the GNU General Public License | |
2379 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
2380 | + */ | |
2381 | + | |
2382 | +#include <linux/module.h> | |
2383 | +#include <linux/etherdevice.h> | |
2384 | +#include <linux/mii.h> | |
2385 | +#include <linux/usb.h> | |
2386 | +#include <linux/crc32.h> | |
2387 | +#include <linux/usb/usbnet.h> | |
2388 | +#include <uapi/linux/mdio.h> | |
2389 | +#include <linux/mdio.h> | |
2390 | + | |
2391 | +#define AX88179_PHY_ID 0x03 | |
2392 | +#define AX_EEPROM_LEN 0x100 | |
2393 | +#define AX88179_EEPROM_MAGIC 0x17900b95 | |
2394 | +#define AX_MCAST_FLTSIZE 8 | |
2395 | +#define AX_MAX_MCAST 64 | |
2396 | +#define AX_INT_PPLS_LINK ((u32)BIT(16)) | |
2397 | +#define AX_RXHDR_L4_TYPE_MASK 0x1c | |
2398 | +#define AX_RXHDR_L4_TYPE_UDP 4 | |
2399 | +#define AX_RXHDR_L4_TYPE_TCP 16 | |
2400 | +#define AX_RXHDR_L3CSUM_ERR 2 | |
2401 | +#define AX_RXHDR_L4CSUM_ERR 1 | |
2402 | +#define AX_RXHDR_CRC_ERR ((u32)BIT(29)) | |
2403 | +#define AX_RXHDR_DROP_ERR ((u32)BIT(31)) | |
2404 | +#define AX_ACCESS_MAC 0x01 | |
2405 | +#define AX_ACCESS_PHY 0x02 | |
2406 | +#define AX_ACCESS_EEPROM 0x04 | |
2407 | +#define AX_ACCESS_EFUS 0x05 | |
2408 | +#define AX_PAUSE_WATERLVL_HIGH 0x54 | |
2409 | +#define AX_PAUSE_WATERLVL_LOW 0x55 | |
2410 | + | |
2411 | +#define PHYSICAL_LINK_STATUS 0x02 | |
2412 | + #define AX_USB_SS 0x04 | |
2413 | + #define AX_USB_HS 0x02 | |
2414 | + | |
2415 | +#define GENERAL_STATUS 0x03 | |
2416 | +/* Check AX88179 version. UA1:Bit2 = 0, UA2:Bit2 = 1 */ | |
2417 | + #define AX_SECLD 0x04 | |
2418 | + | |
2419 | +#define AX_SROM_ADDR 0x07 | |
2420 | +#define AX_SROM_CMD 0x0a | |
2421 | + #define EEP_RD 0x04 | |
2422 | + #define EEP_BUSY 0x10 | |
2423 | + | |
2424 | +#define AX_SROM_DATA_LOW 0x08 | |
2425 | +#define AX_SROM_DATA_HIGH 0x09 | |
2426 | + | |
2427 | +#define AX_RX_CTL 0x0b | |
2428 | + #define AX_RX_CTL_DROPCRCERR 0x0100 | |
2429 | + #define AX_RX_CTL_IPE 0x0200 | |
2430 | + #define AX_RX_CTL_START 0x0080 | |
2431 | + #define AX_RX_CTL_AP 0x0020 | |
2432 | + #define AX_RX_CTL_AM 0x0010 | |
2433 | + #define AX_RX_CTL_AB 0x0008 | |
2434 | + #define AX_RX_CTL_AMALL 0x0002 | |
2435 | + #define AX_RX_CTL_PRO 0x0001 | |
2436 | + #define AX_RX_CTL_STOP 0x0000 | |
2437 | + | |
2438 | +#define AX_NODE_ID 0x10 | |
2439 | +#define AX_MULFLTARY 0x16 | |
2440 | + | |
2441 | +#define AX_MEDIUM_STATUS_MODE 0x22 | |
2442 | + #define AX_MEDIUM_GIGAMODE 0x01 | |
2443 | + #define AX_MEDIUM_FULL_DUPLEX 0x02 | |
2444 | + #define AX_MEDIUM_EN_125MHZ 0x08 | |
2445 | + #define AX_MEDIUM_RXFLOW_CTRLEN 0x10 | |
2446 | + #define AX_MEDIUM_TXFLOW_CTRLEN 0x20 | |
2447 | + #define AX_MEDIUM_RECEIVE_EN 0x100 | |
2448 | + #define AX_MEDIUM_PS 0x200 | |
2449 | + #define AX_MEDIUM_JUMBO_EN 0x8040 | |
2450 | + | |
2451 | +#define AX_MONITOR_MOD 0x24 | |
2452 | + #define AX_MONITOR_MODE_RWLC 0x02 | |
2453 | + #define AX_MONITOR_MODE_RWMP 0x04 | |
2454 | + #define AX_MONITOR_MODE_PMEPOL 0x20 | |
2455 | + #define AX_MONITOR_MODE_PMETYPE 0x40 | |
2456 | + | |
2457 | +#define AX_GPIO_CTRL 0x25 | |
2458 | + #define AX_GPIO_CTRL_GPIO3EN 0x80 | |
2459 | + #define AX_GPIO_CTRL_GPIO2EN 0x40 | |
2460 | + #define AX_GPIO_CTRL_GPIO1EN 0x20 | |
2461 | + | |
2462 | +#define AX_PHYPWR_RSTCTL 0x26 | |
2463 | + #define AX_PHYPWR_RSTCTL_BZ 0x0010 | |
2464 | + #define AX_PHYPWR_RSTCTL_IPRL 0x0020 | |
2465 | + #define AX_PHYPWR_RSTCTL_AT 0x1000 | |
2466 | + | |
2467 | +#define AX_RX_BULKIN_QCTRL 0x2e | |
2468 | +#define AX_CLK_SELECT 0x33 | |
2469 | + #define AX_CLK_SELECT_BCS 0x01 | |
2470 | + #define AX_CLK_SELECT_ACS 0x02 | |
2471 | + #define AX_CLK_SELECT_ULR 0x08 | |
2472 | + | |
2473 | +#define AX_RXCOE_CTL 0x34 | |
2474 | + #define AX_RXCOE_IP 0x01 | |
2475 | + #define AX_RXCOE_TCP 0x02 | |
2476 | + #define AX_RXCOE_UDP 0x04 | |
2477 | + #define AX_RXCOE_TCPV6 0x20 | |
2478 | + #define AX_RXCOE_UDPV6 0x40 | |
2479 | + | |
2480 | +#define AX_TXCOE_CTL 0x35 | |
2481 | + #define AX_TXCOE_IP 0x01 | |
2482 | + #define AX_TXCOE_TCP 0x02 | |
2483 | + #define AX_TXCOE_UDP 0x04 | |
2484 | + #define AX_TXCOE_TCPV6 0x20 | |
2485 | + #define AX_TXCOE_UDPV6 0x40 | |
2486 | + | |
2487 | +#define AX_LEDCTRL 0x73 | |
2488 | + | |
2489 | +#define GMII_PHY_PHYSR 0x11 | |
2490 | + #define GMII_PHY_PHYSR_SMASK 0xc000 | |
2491 | + #define GMII_PHY_PHYSR_GIGA 0x8000 | |
2492 | + #define GMII_PHY_PHYSR_100 0x4000 | |
2493 | + #define GMII_PHY_PHYSR_FULL 0x2000 | |
2494 | + #define GMII_PHY_PHYSR_LINK 0x400 | |
2495 | + | |
2496 | +#define GMII_LED_ACT 0x1a | |
2497 | + #define GMII_LED_ACTIVE_MASK 0xff8f | |
2498 | + #define GMII_LED0_ACTIVE BIT(4) | |
2499 | + #define GMII_LED1_ACTIVE BIT(5) | |
2500 | + #define GMII_LED2_ACTIVE BIT(6) | |
2501 | + | |
2502 | +#define GMII_LED_LINK 0x1c | |
2503 | + #define GMII_LED_LINK_MASK 0xf888 | |
2504 | + #define GMII_LED0_LINK_10 BIT(0) | |
2505 | + #define GMII_LED0_LINK_100 BIT(1) | |
2506 | + #define GMII_LED0_LINK_1000 BIT(2) | |
2507 | + #define GMII_LED1_LINK_10 BIT(4) | |
2508 | + #define GMII_LED1_LINK_100 BIT(5) | |
2509 | + #define GMII_LED1_LINK_1000 BIT(6) | |
2510 | + #define GMII_LED2_LINK_10 BIT(8) | |
2511 | + #define GMII_LED2_LINK_100 BIT(9) | |
2512 | + #define GMII_LED2_LINK_1000 BIT(10) | |
2513 | + #define LED0_ACTIVE BIT(0) | |
2514 | + #define LED0_LINK_10 BIT(1) | |
2515 | + #define LED0_LINK_100 BIT(2) | |
2516 | + #define LED0_LINK_1000 BIT(3) | |
2517 | + #define LED0_FD BIT(4) | |
2518 | + #define LED0_USB3_MASK 0x001f | |
2519 | + #define LED1_ACTIVE BIT(5) | |
2520 | + #define LED1_LINK_10 BIT(6) | |
2521 | + #define LED1_LINK_100 BIT(7) | |
2522 | + #define LED1_LINK_1000 BIT(8) | |
2523 | + #define LED1_FD BIT(9) | |
2524 | + #define LED1_USB3_MASK 0x03e0 | |
2525 | + #define LED2_ACTIVE BIT(10) | |
2526 | + #define LED2_LINK_1000 BIT(13) | |
2527 | + #define LED2_LINK_100 BIT(12) | |
2528 | + #define LED2_LINK_10 BIT(11) | |
2529 | + #define LED2_FD BIT(14) | |
2530 | + #define LED_VALID BIT(15) | |
2531 | + #define LED2_USB3_MASK 0x7c00 | |
2532 | + | |
2533 | +#define GMII_PHYPAGE 0x1e | |
2534 | +#define GMII_PHY_PAGE_SELECT 0x1f | |
2535 | + #define GMII_PHY_PGSEL_EXT 0x0007 | |
2536 | + #define GMII_PHY_PGSEL_PAGE0 0x0000 | |
2537 | + #define GMII_PHY_PGSEL_PAGE3 0x0003 | |
2538 | + #define GMII_PHY_PGSEL_PAGE5 0x0005 | |
2539 | + | |
2540 | +struct ax88179_data { | |
2541 | + u8 eee_enabled; | |
2542 | + u8 eee_active; | |
2543 | + u16 rxctl; | |
2544 | + u16 reserved; | |
2545 | +}; | |
2546 | + | |
2547 | +struct ax88179_int_data { | |
2548 | + __le32 intdata1; | |
2549 | + __le32 intdata2; | |
2550 | +}; | |
2551 | + | |
2552 | +static const struct { | |
2553 | + unsigned char ctrl, timer_l, timer_h, size, ifg; | |
2554 | +} AX88179_BULKIN_SIZE[] = { | |
2555 | + {7, 0x4f, 0, 0x12, 0xff}, | |
2556 | + {7, 0x20, 3, 0x16, 0xff}, | |
2557 | + {7, 0xae, 7, 0x18, 0xff}, | |
2558 | + {7, 0xcc, 0x4c, 0x18, 8}, | |
2559 | +}; | |
2560 | + | |
2561 | +static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
2562 | + u16 size, void *data, int in_pm) | |
2563 | +{ | |
2564 | + int ret; | |
2565 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); | |
2566 | + | |
2567 | + BUG_ON(!dev); | |
2568 | + | |
2569 | + if (!in_pm) | |
2570 | + fn = usbnet_read_cmd; | |
2571 | + else | |
2572 | + fn = usbnet_read_cmd_nopm; | |
2573 | + | |
2574 | + ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
2575 | + value, index, data, size); | |
2576 | + | |
2577 | + if (unlikely(ret < 0)) | |
2578 | + netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n", | |
2579 | + index, ret); | |
2580 | + | |
2581 | + return ret; | |
2582 | +} | |
2583 | + | |
2584 | +static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
2585 | + u16 size, void *data, int in_pm) | |
2586 | +{ | |
2587 | + int ret; | |
2588 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16); | |
2589 | + | |
2590 | + BUG_ON(!dev); | |
2591 | + | |
2592 | + if (!in_pm) | |
2593 | + fn = usbnet_write_cmd; | |
2594 | + else | |
2595 | + fn = usbnet_write_cmd_nopm; | |
2596 | + | |
2597 | + ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
2598 | + value, index, data, size); | |
2599 | + | |
2600 | + if (unlikely(ret < 0)) | |
2601 | + netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n", | |
2602 | + index, ret); | |
2603 | + | |
2604 | + return ret; | |
2605 | +} | |
2606 | + | |
2607 | +static void ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, | |
2608 | + u16 index, u16 size, void *data) | |
2609 | +{ | |
2610 | + u16 buf; | |
2611 | + | |
2612 | + if (2 == size) { | |
2613 | + buf = *((u16 *)data); | |
2614 | + cpu_to_le16s(&buf); | |
2615 | + usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | | |
2616 | + USB_RECIP_DEVICE, value, index, &buf, | |
2617 | + size); | |
2618 | + } else { | |
2619 | + usbnet_write_cmd_async(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | | |
2620 | + USB_RECIP_DEVICE, value, index, data, | |
2621 | + size); | |
2622 | + } | |
2623 | +} | |
2624 | + | |
2625 | +static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, | |
2626 | + u16 index, u16 size, void *data) | |
2627 | +{ | |
2628 | + int ret; | |
2629 | + | |
2630 | + if (2 == size) { | |
2631 | + u16 buf; | |
2632 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); | |
2633 | + le16_to_cpus(&buf); | |
2634 | + *((u16 *)data) = buf; | |
2635 | + } else if (4 == size) { | |
2636 | + u32 buf; | |
2637 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1); | |
2638 | + le32_to_cpus(&buf); | |
2639 | + *((u32 *)data) = buf; | |
2640 | + } else { | |
2641 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1); | |
2642 | + } | |
2643 | + | |
2644 | + return ret; | |
2645 | +} | |
2646 | + | |
2647 | +static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, | |
2648 | + u16 index, u16 size, void *data) | |
2649 | +{ | |
2650 | + int ret; | |
2651 | + | |
2652 | + if (2 == size) { | |
2653 | + u16 buf; | |
2654 | + buf = *((u16 *)data); | |
2655 | + cpu_to_le16s(&buf); | |
2656 | + ret = __ax88179_write_cmd(dev, cmd, value, index, | |
2657 | + size, &buf, 1); | |
2658 | + } else { | |
2659 | + ret = __ax88179_write_cmd(dev, cmd, value, index, | |
2660 | + size, data, 1); | |
2661 | + } | |
2662 | + | |
2663 | + return ret; | |
2664 | +} | |
2665 | + | |
2666 | +static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
2667 | + u16 size, void *data) | |
2668 | +{ | |
2669 | + int ret; | |
2670 | + | |
2671 | + if (2 == size) { | |
2672 | + u16 buf; | |
2673 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); | |
2674 | + le16_to_cpus(&buf); | |
2675 | + *((u16 *)data) = buf; | |
2676 | + } else if (4 == size) { | |
2677 | + u32 buf; | |
2678 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0); | |
2679 | + le32_to_cpus(&buf); | |
2680 | + *((u32 *)data) = buf; | |
2681 | + } else { | |
2682 | + ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0); | |
2683 | + } | |
2684 | + | |
2685 | + return ret; | |
2686 | +} | |
2687 | + | |
2688 | +static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
2689 | + u16 size, void *data) | |
2690 | +{ | |
2691 | + int ret; | |
2692 | + | |
2693 | + if (2 == size) { | |
2694 | + u16 buf; | |
2695 | + buf = *((u16 *)data); | |
2696 | + cpu_to_le16s(&buf); | |
2697 | + ret = __ax88179_write_cmd(dev, cmd, value, index, | |
2698 | + size, &buf, 0); | |
2699 | + } else { | |
2700 | + ret = __ax88179_write_cmd(dev, cmd, value, index, | |
2701 | + size, data, 0); | |
2702 | + } | |
2703 | + | |
2704 | + return ret; | |
2705 | +} | |
2706 | + | |
2707 | +static void ax88179_status(struct usbnet *dev, struct urb *urb) | |
2708 | +{ | |
2709 | + struct ax88179_int_data *event; | |
2710 | + u32 link; | |
2711 | + | |
2712 | + if (urb->actual_length < 8) | |
2713 | + return; | |
2714 | + | |
2715 | + event = urb->transfer_buffer; | |
2716 | + le32_to_cpus((void *)&event->intdata1); | |
2717 | + | |
2718 | + link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16; | |
2719 | + | |
2720 | + if (netif_carrier_ok(dev->net) != link) { | |
2721 | + usbnet_link_change(dev, link, 1); | |
2722 | + netdev_info(dev->net, "ax88179 - Link status is: %d\n", link); | |
2723 | + } | |
2724 | +} | |
2725 | + | |
2726 | +static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc) | |
2727 | +{ | |
2728 | + struct usbnet *dev = netdev_priv(netdev); | |
2729 | + u16 res; | |
2730 | + | |
2731 | + ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); | |
2732 | + return res; | |
2733 | +} | |
2734 | + | |
2735 | +static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, | |
2736 | + int val) | |
2737 | +{ | |
2738 | + struct usbnet *dev = netdev_priv(netdev); | |
2739 | + u16 res = (u16) val; | |
2740 | + | |
2741 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); | |
2742 | +} | |
2743 | + | |
2744 | +static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad, | |
2745 | + u16 devad) | |
2746 | +{ | |
2747 | + u16 tmp16; | |
2748 | + int ret; | |
2749 | + | |
2750 | + tmp16 = devad; | |
2751 | + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
2752 | + MII_MMD_CTRL, 2, &tmp16); | |
2753 | + | |
2754 | + tmp16 = prtad; | |
2755 | + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
2756 | + MII_MMD_DATA, 2, &tmp16); | |
2757 | + | |
2758 | + tmp16 = devad | MII_MMD_CTRL_NOINCR; | |
2759 | + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
2760 | + MII_MMD_CTRL, 2, &tmp16); | |
2761 | + | |
2762 | + return ret; | |
2763 | +} | |
2764 | + | |
2765 | +static int | |
2766 | +ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad) | |
2767 | +{ | |
2768 | + int ret; | |
2769 | + u16 tmp16; | |
2770 | + | |
2771 | + ax88179_phy_mmd_indirect(dev, prtad, devad); | |
2772 | + | |
2773 | + ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
2774 | + MII_MMD_DATA, 2, &tmp16); | |
2775 | + if (ret < 0) | |
2776 | + return ret; | |
2777 | + | |
2778 | + return tmp16; | |
2779 | +} | |
2780 | + | |
2781 | +static int | |
2782 | +ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad, | |
2783 | + u16 data) | |
2784 | +{ | |
2785 | + int ret; | |
2786 | + | |
2787 | + ax88179_phy_mmd_indirect(dev, prtad, devad); | |
2788 | + | |
2789 | + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
2790 | + MII_MMD_DATA, 2, &data); | |
2791 | + | |
2792 | + if (ret < 0) | |
2793 | + return ret; | |
2794 | + | |
2795 | + return 0; | |
2796 | +} | |
2797 | + | |
2798 | +static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) | |
2799 | +{ | |
2800 | + struct usbnet *dev = usb_get_intfdata(intf); | |
2801 | + u16 tmp16; | |
2802 | + u8 tmp8; | |
2803 | + | |
2804 | + usbnet_suspend(intf, message); | |
2805 | + | |
2806 | + /* Disable RX path */ | |
2807 | + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
2808 | + 2, 2, &tmp16); | |
2809 | + tmp16 &= ~AX_MEDIUM_RECEIVE_EN; | |
2810 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
2811 | + 2, 2, &tmp16); | |
2812 | + | |
2813 | + /* Force bulk-in zero length */ | |
2814 | + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, | |
2815 | + 2, 2, &tmp16); | |
2816 | + | |
2817 | + tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL; | |
2818 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, | |
2819 | + 2, 2, &tmp16); | |
2820 | + | |
2821 | + /* change clock */ | |
2822 | + tmp8 = 0; | |
2823 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); | |
2824 | + | |
2825 | + /* Configure RX control register => stop operation */ | |
2826 | + tmp16 = AX_RX_CTL_STOP; | |
2827 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); | |
2828 | + | |
2829 | + return 0; | |
2830 | +} | |
2831 | + | |
2832 | +/* This function is used to enable the autodetach function. */ | |
2833 | +/* This function is determined by offset 0x43 of EEPROM */ | |
2834 | +static int ax88179_auto_detach(struct usbnet *dev, int in_pm) | |
2835 | +{ | |
2836 | + u16 tmp16; | |
2837 | + u8 tmp8; | |
2838 | + int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *); | |
2839 | + int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *); | |
2840 | + | |
2841 | + if (!in_pm) { | |
2842 | + fnr = ax88179_read_cmd; | |
2843 | + fnw = ax88179_write_cmd; | |
2844 | + } else { | |
2845 | + fnr = ax88179_read_cmd_nopm; | |
2846 | + fnw = ax88179_write_cmd_nopm; | |
2847 | + } | |
2848 | + | |
2849 | + if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16) < 0) | |
2850 | + return 0; | |
2851 | + | |
2852 | + if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100))) | |
2853 | + return 0; | |
2854 | + | |
2855 | + /* Enable Auto Detach bit */ | |
2856 | + tmp8 = 0; | |
2857 | + fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); | |
2858 | + tmp8 |= AX_CLK_SELECT_ULR; | |
2859 | + fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); | |
2860 | + | |
2861 | + fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); | |
2862 | + tmp16 |= AX_PHYPWR_RSTCTL_AT; | |
2863 | + fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); | |
2864 | + | |
2865 | + return 0; | |
2866 | +} | |
2867 | + | |
2868 | +static int ax88179_resume(struct usb_interface *intf) | |
2869 | +{ | |
2870 | + struct usbnet *dev = usb_get_intfdata(intf); | |
2871 | + u16 tmp16; | |
2872 | + u8 tmp8; | |
2873 | + | |
2874 | + usbnet_link_change(dev, 0, 0); | |
2875 | + | |
2876 | + /* Power up ethernet PHY */ | |
2877 | + tmp16 = 0; | |
2878 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, | |
2879 | + 2, 2, &tmp16); | |
2880 | + udelay(1000); | |
2881 | + | |
2882 | + tmp16 = AX_PHYPWR_RSTCTL_IPRL; | |
2883 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, | |
2884 | + 2, 2, &tmp16); | |
2885 | + msleep(200); | |
2886 | + | |
2887 | + /* Ethernet PHY Auto Detach*/ | |
2888 | + ax88179_auto_detach(dev, 1); | |
2889 | + | |
2890 | + /* Enable clock */ | |
2891 | + ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); | |
2892 | + tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; | |
2893 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8); | |
2894 | + msleep(100); | |
2895 | + | |
2896 | + /* Configure RX control register => start operation */ | |
2897 | + tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | | |
2898 | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; | |
2899 | + ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); | |
2900 | + | |
2901 | + return usbnet_resume(intf); | |
2902 | +} | |
2903 | + | |
2904 | +static void | |
2905 | +ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
2906 | +{ | |
2907 | + struct usbnet *dev = netdev_priv(net); | |
2908 | + u8 opt; | |
2909 | + | |
2910 | + if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, | |
2911 | + 1, 1, &opt) < 0) { | |
2912 | + wolinfo->supported = 0; | |
2913 | + wolinfo->wolopts = 0; | |
2914 | + return; | |
2915 | + } | |
2916 | + | |
2917 | + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | |
2918 | + wolinfo->wolopts = 0; | |
2919 | + if (opt & AX_MONITOR_MODE_RWLC) | |
2920 | + wolinfo->wolopts |= WAKE_PHY; | |
2921 | + if (opt & AX_MONITOR_MODE_RWMP) | |
2922 | + wolinfo->wolopts |= WAKE_MAGIC; | |
2923 | +} | |
2924 | + | |
2925 | +static int | |
2926 | +ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
2927 | +{ | |
2928 | + struct usbnet *dev = netdev_priv(net); | |
2929 | + u8 opt = 0; | |
2930 | + | |
2931 | + if (wolinfo->wolopts & WAKE_PHY) | |
2932 | + opt |= AX_MONITOR_MODE_RWLC; | |
2933 | + if (wolinfo->wolopts & WAKE_MAGIC) | |
2934 | + opt |= AX_MONITOR_MODE_RWMP; | |
2935 | + | |
2936 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, | |
2937 | + 1, 1, &opt) < 0) | |
2938 | + return -EINVAL; | |
2939 | + | |
2940 | + return 0; | |
2941 | +} | |
2942 | + | |
2943 | +static int ax88179_get_eeprom_len(struct net_device *net) | |
2944 | +{ | |
2945 | + return AX_EEPROM_LEN; | |
2946 | +} | |
2947 | + | |
2948 | +static int | |
2949 | +ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |
2950 | + u8 *data) | |
2951 | +{ | |
2952 | + struct usbnet *dev = netdev_priv(net); | |
2953 | + u16 *eeprom_buff; | |
2954 | + int first_word, last_word; | |
2955 | + int i, ret; | |
2956 | + | |
2957 | + if (eeprom->len == 0) | |
2958 | + return -EINVAL; | |
2959 | + | |
2960 | + eeprom->magic = AX88179_EEPROM_MAGIC; | |
2961 | + | |
2962 | + first_word = eeprom->offset >> 1; | |
2963 | + last_word = (eeprom->offset + eeprom->len - 1) >> 1; | |
2964 | + eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | |
2965 | + GFP_KERNEL); | |
2966 | + if (!eeprom_buff) | |
2967 | + return -ENOMEM; | |
2968 | + | |
2969 | + /* ax88179/178A returns 2 bytes from eeprom on read */ | |
2970 | + for (i = first_word; i <= last_word; i++) { | |
2971 | + ret = __ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2, | |
2972 | + &eeprom_buff[i - first_word], | |
2973 | + 0); | |
2974 | + if (ret < 0) { | |
2975 | + kfree(eeprom_buff); | |
2976 | + return -EIO; | |
2977 | + } | |
2978 | + } | |
2979 | + | |
2980 | + memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); | |
2981 | + kfree(eeprom_buff); | |
2982 | + return 0; | |
2983 | +} | |
2984 | + | |
2985 | +static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd) | |
2986 | +{ | |
2987 | + struct usbnet *dev = netdev_priv(net); | |
2988 | + return mii_ethtool_gset(&dev->mii, cmd); | |
2989 | +} | |
2990 | + | |
2991 | +static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd) | |
2992 | +{ | |
2993 | + struct usbnet *dev = netdev_priv(net); | |
2994 | + return mii_ethtool_sset(&dev->mii, cmd); | |
2995 | +} | |
2996 | + | |
2997 | +static int | |
2998 | +ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) | |
2999 | +{ | |
3000 | + int val; | |
3001 | + | |
3002 | + /* Get Supported EEE */ | |
3003 | + val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE, | |
3004 | + MDIO_MMD_PCS); | |
3005 | + if (val < 0) | |
3006 | + return val; | |
3007 | + data->supported = mmd_eee_cap_to_ethtool_sup_t(val); | |
3008 | + | |
3009 | + /* Get advertisement EEE */ | |
3010 | + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, | |
3011 | + MDIO_MMD_AN); | |
3012 | + if (val < 0) | |
3013 | + return val; | |
3014 | + data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); | |
3015 | + | |
3016 | + /* Get LP advertisement EEE */ | |
3017 | + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, | |
3018 | + MDIO_MMD_AN); | |
3019 | + if (val < 0) | |
3020 | + return val; | |
3021 | + data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); | |
3022 | + | |
3023 | + return 0; | |
3024 | +} | |
3025 | + | |
3026 | +static int | |
3027 | +ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data) | |
3028 | +{ | |
3029 | + u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); | |
3030 | + | |
3031 | + return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, | |
3032 | + MDIO_MMD_AN, tmp16); | |
3033 | +} | |
3034 | + | |
3035 | +static int ax88179_chk_eee(struct usbnet *dev) | |
3036 | +{ | |
3037 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
3038 | + struct ax88179_data *priv = (struct ax88179_data *)dev->data; | |
3039 | + | |
3040 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
3041 | + | |
3042 | + if (ecmd.duplex & DUPLEX_FULL) { | |
3043 | + int eee_lp, eee_cap, eee_adv; | |
3044 | + u32 lp, cap, adv, supported = 0; | |
3045 | + | |
3046 | + eee_cap = ax88179_phy_read_mmd_indirect(dev, | |
3047 | + MDIO_PCS_EEE_ABLE, | |
3048 | + MDIO_MMD_PCS); | |
3049 | + if (eee_cap < 0) { | |
3050 | + priv->eee_active = 0; | |
3051 | + return false; | |
3052 | + } | |
3053 | + | |
3054 | + cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap); | |
3055 | + if (!cap) { | |
3056 | + priv->eee_active = 0; | |
3057 | + return false; | |
3058 | + } | |
3059 | + | |
3060 | + eee_lp = ax88179_phy_read_mmd_indirect(dev, | |
3061 | + MDIO_AN_EEE_LPABLE, | |
3062 | + MDIO_MMD_AN); | |
3063 | + if (eee_lp < 0) { | |
3064 | + priv->eee_active = 0; | |
3065 | + return false; | |
3066 | + } | |
3067 | + | |
3068 | + eee_adv = ax88179_phy_read_mmd_indirect(dev, | |
3069 | + MDIO_AN_EEE_ADV, | |
3070 | + MDIO_MMD_AN); | |
3071 | + | |
3072 | + if (eee_adv < 0) { | |
3073 | + priv->eee_active = 0; | |
3074 | + return false; | |
3075 | + } | |
3076 | + | |
3077 | + adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); | |
3078 | + lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); | |
3079 | + supported = (ecmd.speed == SPEED_1000) ? | |
3080 | + SUPPORTED_1000baseT_Full : | |
3081 | + SUPPORTED_100baseT_Full; | |
3082 | + | |
3083 | + if (!(lp & adv & supported)) { | |
3084 | + priv->eee_active = 0; | |
3085 | + return false; | |
3086 | + } | |
3087 | + | |
3088 | + priv->eee_active = 1; | |
3089 | + return true; | |
3090 | + } | |
3091 | + | |
3092 | + priv->eee_active = 0; | |
3093 | + return false; | |
3094 | +} | |
3095 | + | |
3096 | +static void ax88179_disable_eee(struct usbnet *dev) | |
3097 | +{ | |
3098 | + u16 tmp16; | |
3099 | + | |
3100 | + tmp16 = GMII_PHY_PGSEL_PAGE3; | |
3101 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3102 | + GMII_PHY_PAGE_SELECT, 2, &tmp16); | |
3103 | + | |
3104 | + tmp16 = 0x3246; | |
3105 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3106 | + MII_PHYADDR, 2, &tmp16); | |
3107 | + | |
3108 | + tmp16 = GMII_PHY_PGSEL_PAGE0; | |
3109 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3110 | + GMII_PHY_PAGE_SELECT, 2, &tmp16); | |
3111 | +} | |
3112 | + | |
3113 | +static void ax88179_enable_eee(struct usbnet *dev) | |
3114 | +{ | |
3115 | + u16 tmp16; | |
3116 | + | |
3117 | + tmp16 = GMII_PHY_PGSEL_PAGE3; | |
3118 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3119 | + GMII_PHY_PAGE_SELECT, 2, &tmp16); | |
3120 | + | |
3121 | + tmp16 = 0x3247; | |
3122 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3123 | + MII_PHYADDR, 2, &tmp16); | |
3124 | + | |
3125 | + tmp16 = GMII_PHY_PGSEL_PAGE5; | |
3126 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3127 | + GMII_PHY_PAGE_SELECT, 2, &tmp16); | |
3128 | + | |
3129 | + tmp16 = 0x0680; | |
3130 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3131 | + MII_BMSR, 2, &tmp16); | |
3132 | + | |
3133 | + tmp16 = GMII_PHY_PGSEL_PAGE0; | |
3134 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3135 | + GMII_PHY_PAGE_SELECT, 2, &tmp16); | |
3136 | +} | |
3137 | + | |
3138 | +static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) | |
3139 | +{ | |
3140 | + struct usbnet *dev = netdev_priv(net); | |
3141 | + struct ax88179_data *priv = (struct ax88179_data *)dev->data; | |
3142 | + | |
3143 | + edata->eee_enabled = priv->eee_enabled; | |
3144 | + edata->eee_active = priv->eee_active; | |
3145 | + | |
3146 | + return ax88179_ethtool_get_eee(dev, edata); | |
3147 | +} | |
3148 | + | |
3149 | +static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata) | |
3150 | +{ | |
3151 | + struct usbnet *dev = netdev_priv(net); | |
3152 | + struct ax88179_data *priv = (struct ax88179_data *)dev->data; | |
3153 | + int ret = -EOPNOTSUPP; | |
3154 | + | |
3155 | + priv->eee_enabled = edata->eee_enabled; | |
3156 | + if (!priv->eee_enabled) { | |
3157 | + ax88179_disable_eee(dev); | |
3158 | + } else { | |
3159 | + priv->eee_enabled = ax88179_chk_eee(dev); | |
3160 | + if (!priv->eee_enabled) | |
3161 | + return -EOPNOTSUPP; | |
3162 | + | |
3163 | + ax88179_enable_eee(dev); | |
3164 | + } | |
3165 | + | |
3166 | + ret = ax88179_ethtool_set_eee(dev, edata); | |
3167 | + if (ret) | |
3168 | + return ret; | |
3169 | + | |
3170 | + mii_nway_restart(&dev->mii); | |
3171 | + | |
3172 | + usbnet_link_change(dev, 0, 0); | |
3173 | + | |
3174 | + return ret; | |
3175 | +} | |
3176 | + | |
3177 | +static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
3178 | +{ | |
3179 | + struct usbnet *dev = netdev_priv(net); | |
3180 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
3181 | +} | |
3182 | + | |
3183 | +static const struct ethtool_ops ax88179_ethtool_ops = { | |
3184 | + .get_link = ethtool_op_get_link, | |
3185 | + .get_msglevel = usbnet_get_msglevel, | |
3186 | + .set_msglevel = usbnet_set_msglevel, | |
3187 | + .get_wol = ax88179_get_wol, | |
3188 | + .set_wol = ax88179_set_wol, | |
3189 | + .get_eeprom_len = ax88179_get_eeprom_len, | |
3190 | + .get_eeprom = ax88179_get_eeprom, | |
3191 | + .get_settings = ax88179_get_settings, | |
3192 | + .set_settings = ax88179_set_settings, | |
3193 | + .get_eee = ax88179_get_eee, | |
3194 | + .set_eee = ax88179_set_eee, | |
3195 | + .nway_reset = usbnet_nway_reset, | |
3196 | +}; | |
3197 | + | |
3198 | +static void ax88179_set_multicast(struct net_device *net) | |
3199 | +{ | |
3200 | + struct usbnet *dev = netdev_priv(net); | |
3201 | + struct ax88179_data *data = (struct ax88179_data *)dev->data; | |
3202 | + u8 *m_filter = ((u8 *)dev->data) + 12; | |
3203 | + | |
3204 | + data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_IPE); | |
3205 | + | |
3206 | + if (net->flags & IFF_PROMISC) { | |
3207 | + data->rxctl |= AX_RX_CTL_PRO; | |
3208 | + } else if (net->flags & IFF_ALLMULTI || | |
3209 | + netdev_mc_count(net) > AX_MAX_MCAST) { | |
3210 | + data->rxctl |= AX_RX_CTL_AMALL; | |
3211 | + } else if (netdev_mc_empty(net)) { | |
3212 | + /* just broadcast and directed */ | |
3213 | + } else { | |
3214 | + /* We use the 20 byte dev->data for our 8 byte filter buffer | |
3215 | + * to avoid allocating memory that is tricky to free later | |
3216 | + */ | |
3217 | + u32 crc_bits; | |
3218 | + struct netdev_hw_addr *ha; | |
3219 | + | |
3220 | + memset(m_filter, 0, AX_MCAST_FLTSIZE); | |
3221 | + | |
3222 | + netdev_for_each_mc_addr(ha, net) { | |
3223 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
3224 | + *(m_filter + (crc_bits >> 3)) |= (1 << (crc_bits & 7)); | |
3225 | + } | |
3226 | + | |
3227 | + ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_MULFLTARY, | |
3228 | + AX_MCAST_FLTSIZE, AX_MCAST_FLTSIZE, | |
3229 | + m_filter); | |
3230 | + | |
3231 | + data->rxctl |= AX_RX_CTL_AM; | |
3232 | + } | |
3233 | + | |
3234 | + ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL, | |
3235 | + 2, 2, &data->rxctl); | |
3236 | +} | |
3237 | + | |
3238 | +static int | |
3239 | +ax88179_set_features(struct net_device *net, netdev_features_t features) | |
3240 | +{ | |
3241 | + u8 tmp; | |
3242 | + struct usbnet *dev = netdev_priv(net); | |
3243 | + netdev_features_t changed = net->features ^ features; | |
3244 | + | |
3245 | + if (changed & NETIF_F_IP_CSUM) { | |
3246 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); | |
3247 | + tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP; | |
3248 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); | |
3249 | + } | |
3250 | + | |
3251 | + if (changed & NETIF_F_IPV6_CSUM) { | |
3252 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); | |
3253 | + tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; | |
3254 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp); | |
3255 | + } | |
3256 | + | |
3257 | + if (changed & NETIF_F_RXCSUM) { | |
3258 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); | |
3259 | + tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | | |
3260 | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; | |
3261 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp); | |
3262 | + } | |
3263 | + | |
3264 | + return 0; | |
3265 | +} | |
3266 | + | |
3267 | +static int ax88179_change_mtu(struct net_device *net, int new_mtu) | |
3268 | +{ | |
3269 | + struct usbnet *dev = netdev_priv(net); | |
3270 | + u16 tmp16; | |
3271 | + | |
3272 | + if (new_mtu <= 0 || new_mtu > 4088) | |
3273 | + return -EINVAL; | |
3274 | + | |
3275 | + net->mtu = new_mtu; | |
3276 | + dev->hard_mtu = net->mtu + net->hard_header_len; | |
3277 | + | |
3278 | + if (net->mtu > 1500) { | |
3279 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3280 | + 2, 2, &tmp16); | |
3281 | + tmp16 |= AX_MEDIUM_JUMBO_EN; | |
3282 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3283 | + 2, 2, &tmp16); | |
3284 | + } else { | |
3285 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3286 | + 2, 2, &tmp16); | |
3287 | + tmp16 &= ~AX_MEDIUM_JUMBO_EN; | |
3288 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3289 | + 2, 2, &tmp16); | |
3290 | + } | |
3291 | + | |
3292 | + /* max qlen depend on hard_mtu and rx_urb_size */ | |
3293 | + usbnet_update_max_qlen(dev); | |
3294 | + | |
3295 | + return 0; | |
3296 | +} | |
3297 | + | |
3298 | +static int ax88179_set_mac_addr(struct net_device *net, void *p) | |
3299 | +{ | |
3300 | + struct usbnet *dev = netdev_priv(net); | |
3301 | + struct sockaddr *addr = p; | |
3302 | + int ret; | |
3303 | + | |
3304 | + if (netif_running(net)) | |
3305 | + return -EBUSY; | |
3306 | + if (!is_valid_ether_addr(addr->sa_data)) | |
3307 | + return -EADDRNOTAVAIL; | |
3308 | + | |
3309 | + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | |
3310 | + | |
3311 | + /* Set the MAC address */ | |
3312 | + ret = ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, | |
3313 | + ETH_ALEN, net->dev_addr); | |
3314 | + if (ret < 0) | |
3315 | + return ret; | |
3316 | + | |
3317 | + return 0; | |
3318 | +} | |
3319 | + | |
3320 | +static const struct net_device_ops ax88179_netdev_ops = { | |
3321 | + .ndo_open = usbnet_open, | |
3322 | + .ndo_stop = usbnet_stop, | |
3323 | + .ndo_start_xmit = usbnet_start_xmit, | |
3324 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
3325 | + .ndo_change_mtu = ax88179_change_mtu, | |
3326 | + .ndo_set_mac_address = ax88179_set_mac_addr, | |
3327 | + .ndo_validate_addr = eth_validate_addr, | |
3328 | + .ndo_do_ioctl = ax88179_ioctl, | |
3329 | + .ndo_set_rx_mode = ax88179_set_multicast, | |
3330 | + .ndo_set_features = ax88179_set_features, | |
3331 | +}; | |
3332 | + | |
3333 | +static int ax88179_check_eeprom(struct usbnet *dev) | |
3334 | +{ | |
3335 | + u8 i, buf, eeprom[20]; | |
3336 | + u16 csum, delay = HZ / 10; | |
3337 | + unsigned long jtimeout; | |
3338 | + | |
3339 | + /* Read EEPROM content */ | |
3340 | + for (i = 0; i < 6; i++) { | |
3341 | + buf = i; | |
3342 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, | |
3343 | + 1, 1, &buf) < 0) | |
3344 | + return -EINVAL; | |
3345 | + | |
3346 | + buf = EEP_RD; | |
3347 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, | |
3348 | + 1, 1, &buf) < 0) | |
3349 | + return -EINVAL; | |
3350 | + | |
3351 | + jtimeout = jiffies + delay; | |
3352 | + do { | |
3353 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, | |
3354 | + 1, 1, &buf); | |
3355 | + | |
3356 | + if (time_after(jiffies, jtimeout)) | |
3357 | + return -EINVAL; | |
3358 | + | |
3359 | + } while (buf & EEP_BUSY); | |
3360 | + | |
3361 | + __ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, | |
3362 | + 2, 2, &eeprom[i * 2], 0); | |
3363 | + | |
3364 | + if ((i == 0) && (eeprom[0] == 0xFF)) | |
3365 | + return -EINVAL; | |
3366 | + } | |
3367 | + | |
3368 | + csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; | |
3369 | + csum = (csum >> 8) + (csum & 0xff); | |
3370 | + if ((csum + eeprom[10]) != 0xff) | |
3371 | + return -EINVAL; | |
3372 | + | |
3373 | + return 0; | |
3374 | +} | |
3375 | + | |
3376 | +static int ax88179_check_efuse(struct usbnet *dev, u16 *ledmode) | |
3377 | +{ | |
3378 | + u8 i; | |
3379 | + u8 efuse[64]; | |
3380 | + u16 csum = 0; | |
3381 | + | |
3382 | + if (ax88179_read_cmd(dev, AX_ACCESS_EFUS, 0, 64, 64, efuse) < 0) | |
3383 | + return -EINVAL; | |
3384 | + | |
3385 | + if (*efuse == 0xFF) | |
3386 | + return -EINVAL; | |
3387 | + | |
3388 | + for (i = 0; i < 64; i++) | |
3389 | + csum = csum + efuse[i]; | |
3390 | + | |
3391 | + while (csum > 255) | |
3392 | + csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF); | |
3393 | + | |
3394 | + if (csum != 0xFF) | |
3395 | + return -EINVAL; | |
3396 | + | |
3397 | + *ledmode = (efuse[51] << 8) | efuse[52]; | |
3398 | + | |
3399 | + return 0; | |
3400 | +} | |
3401 | + | |
3402 | +static int ax88179_convert_old_led(struct usbnet *dev, u16 *ledvalue) | |
3403 | +{ | |
3404 | + u16 led; | |
3405 | + | |
3406 | + /* Loaded the old eFuse LED Mode */ | |
3407 | + if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C, 1, 2, &led) < 0) | |
3408 | + return -EINVAL; | |
3409 | + | |
3410 | + led >>= 8; | |
3411 | + switch (led) { | |
3412 | + case 0xFF: | |
3413 | + led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | | |
3414 | + LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | | |
3415 | + LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; | |
3416 | + break; | |
3417 | + case 0xFE: | |
3418 | + led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID; | |
3419 | + break; | |
3420 | + case 0xFD: | |
3421 | + led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | | |
3422 | + LED2_LINK_10 | LED_VALID; | |
3423 | + break; | |
3424 | + case 0xFC: | |
3425 | + led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE | | |
3426 | + LED2_LINK_100 | LED2_LINK_10 | LED_VALID; | |
3427 | + break; | |
3428 | + default: | |
3429 | + led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 | | |
3430 | + LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 | | |
3431 | + LED2_LINK_100 | LED2_LINK_1000 | LED_VALID; | |
3432 | + break; | |
3433 | + } | |
3434 | + | |
3435 | + *ledvalue = led; | |
3436 | + | |
3437 | + return 0; | |
3438 | +} | |
3439 | + | |
3440 | +static int ax88179_led_setting(struct usbnet *dev) | |
3441 | +{ | |
3442 | + u8 ledfd, value = 0; | |
3443 | + u16 tmp, ledact, ledlink, ledvalue = 0, delay = HZ / 10; | |
3444 | + unsigned long jtimeout; | |
3445 | + | |
3446 | + /* Check AX88179 version. UA1 or UA2*/ | |
3447 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value); | |
3448 | + | |
3449 | + if (!(value & AX_SECLD)) { /* UA1 */ | |
3450 | + value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN | | |
3451 | + AX_GPIO_CTRL_GPIO1EN; | |
3452 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL, | |
3453 | + 1, 1, &value) < 0) | |
3454 | + return -EINVAL; | |
3455 | + } | |
3456 | + | |
3457 | + /* Check EEPROM */ | |
3458 | + if (!ax88179_check_eeprom(dev)) { | |
3459 | + value = 0x42; | |
3460 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR, | |
3461 | + 1, 1, &value) < 0) | |
3462 | + return -EINVAL; | |
3463 | + | |
3464 | + value = EEP_RD; | |
3465 | + if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, | |
3466 | + 1, 1, &value) < 0) | |
3467 | + return -EINVAL; | |
3468 | + | |
3469 | + jtimeout = jiffies + delay; | |
3470 | + do { | |
3471 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD, | |
3472 | + 1, 1, &value); | |
3473 | + | |
3474 | + if (time_after(jiffies, jtimeout)) | |
3475 | + return -EINVAL; | |
3476 | + | |
3477 | + } while (value & EEP_BUSY); | |
3478 | + | |
3479 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH, | |
3480 | + 1, 1, &value); | |
3481 | + ledvalue = (value << 8); | |
3482 | + | |
3483 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW, | |
3484 | + 1, 1, &value); | |
3485 | + ledvalue |= value; | |
3486 | + | |
3487 | + /* load internal ROM for defaule setting */ | |
3488 | + if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) | |
3489 | + ax88179_convert_old_led(dev, &ledvalue); | |
3490 | + | |
3491 | + } else if (!ax88179_check_efuse(dev, &ledvalue)) { | |
3492 | + if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0)) | |
3493 | + ax88179_convert_old_led(dev, &ledvalue); | |
3494 | + } else { | |
3495 | + ax88179_convert_old_led(dev, &ledvalue); | |
3496 | + } | |
3497 | + | |
3498 | + tmp = GMII_PHY_PGSEL_EXT; | |
3499 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3500 | + GMII_PHY_PAGE_SELECT, 2, &tmp); | |
3501 | + | |
3502 | + tmp = 0x2c; | |
3503 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3504 | + GMII_PHYPAGE, 2, &tmp); | |
3505 | + | |
3506 | + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3507 | + GMII_LED_ACT, 2, &ledact); | |
3508 | + | |
3509 | + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3510 | + GMII_LED_LINK, 2, &ledlink); | |
3511 | + | |
3512 | + ledact &= GMII_LED_ACTIVE_MASK; | |
3513 | + ledlink &= GMII_LED_LINK_MASK; | |
3514 | + | |
3515 | + if (ledvalue & LED0_ACTIVE) | |
3516 | + ledact |= GMII_LED0_ACTIVE; | |
3517 | + | |
3518 | + if (ledvalue & LED1_ACTIVE) | |
3519 | + ledact |= GMII_LED1_ACTIVE; | |
3520 | + | |
3521 | + if (ledvalue & LED2_ACTIVE) | |
3522 | + ledact |= GMII_LED2_ACTIVE; | |
3523 | + | |
3524 | + if (ledvalue & LED0_LINK_10) | |
3525 | + ledlink |= GMII_LED0_LINK_10; | |
3526 | + | |
3527 | + if (ledvalue & LED1_LINK_10) | |
3528 | + ledlink |= GMII_LED1_LINK_10; | |
3529 | + | |
3530 | + if (ledvalue & LED2_LINK_10) | |
3531 | + ledlink |= GMII_LED2_LINK_10; | |
3532 | + | |
3533 | + if (ledvalue & LED0_LINK_100) | |
3534 | + ledlink |= GMII_LED0_LINK_100; | |
3535 | + | |
3536 | + if (ledvalue & LED1_LINK_100) | |
3537 | + ledlink |= GMII_LED1_LINK_100; | |
3538 | + | |
3539 | + if (ledvalue & LED2_LINK_100) | |
3540 | + ledlink |= GMII_LED2_LINK_100; | |
3541 | + | |
3542 | + if (ledvalue & LED0_LINK_1000) | |
3543 | + ledlink |= GMII_LED0_LINK_1000; | |
3544 | + | |
3545 | + if (ledvalue & LED1_LINK_1000) | |
3546 | + ledlink |= GMII_LED1_LINK_1000; | |
3547 | + | |
3548 | + if (ledvalue & LED2_LINK_1000) | |
3549 | + ledlink |= GMII_LED2_LINK_1000; | |
3550 | + | |
3551 | + tmp = ledact; | |
3552 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3553 | + GMII_LED_ACT, 2, &tmp); | |
3554 | + | |
3555 | + tmp = ledlink; | |
3556 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3557 | + GMII_LED_LINK, 2, &tmp); | |
3558 | + | |
3559 | + tmp = GMII_PHY_PGSEL_PAGE0; | |
3560 | + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3561 | + GMII_PHY_PAGE_SELECT, 2, &tmp); | |
3562 | + | |
3563 | + /* LED full duplex setting */ | |
3564 | + ledfd = 0; | |
3565 | + if (ledvalue & LED0_FD) | |
3566 | + ledfd |= 0x01; | |
3567 | + else if ((ledvalue & LED0_USB3_MASK) == 0) | |
3568 | + ledfd |= 0x02; | |
3569 | + | |
3570 | + if (ledvalue & LED1_FD) | |
3571 | + ledfd |= 0x04; | |
3572 | + else if ((ledvalue & LED1_USB3_MASK) == 0) | |
3573 | + ledfd |= 0x08; | |
3574 | + | |
3575 | + if (ledvalue & LED2_FD) | |
3576 | + ledfd |= 0x10; | |
3577 | + else if ((ledvalue & LED2_USB3_MASK) == 0) | |
3578 | + ledfd |= 0x20; | |
3579 | + | |
3580 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_LEDCTRL, 1, 1, &ledfd); | |
3581 | + | |
3582 | + return 0; | |
3583 | +} | |
3584 | + | |
3585 | +static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) | |
3586 | +{ | |
3587 | + u8 buf[5]; | |
3588 | + u16 *tmp16; | |
3589 | + u8 *tmp; | |
3590 | + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; | |
3591 | + struct ethtool_eee eee_data; | |
3592 | + | |
3593 | + usbnet_get_endpoints(dev, intf); | |
3594 | + | |
3595 | + tmp16 = (u16 *)buf; | |
3596 | + tmp = (u8 *)buf; | |
3597 | + | |
3598 | + memset(ax179_data, 0, sizeof(*ax179_data)); | |
3599 | + | |
3600 | + /* Power up ethernet PHY */ | |
3601 | + *tmp16 = 0; | |
3602 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); | |
3603 | + *tmp16 = AX_PHYPWR_RSTCTL_IPRL; | |
3604 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); | |
3605 | + msleep(200); | |
3606 | + | |
3607 | + *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; | |
3608 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); | |
3609 | + msleep(100); | |
3610 | + | |
3611 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, | |
3612 | + ETH_ALEN, dev->net->dev_addr); | |
3613 | + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); | |
3614 | + | |
3615 | + /* RX bulk configuration */ | |
3616 | + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); | |
3617 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); | |
3618 | + | |
3619 | + dev->rx_urb_size = 1024 * 20; | |
3620 | + | |
3621 | + *tmp = 0x34; | |
3622 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); | |
3623 | + | |
3624 | + *tmp = 0x52; | |
3625 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, | |
3626 | + 1, 1, tmp); | |
3627 | + | |
3628 | + dev->net->netdev_ops = &ax88179_netdev_ops; | |
3629 | + dev->net->ethtool_ops = &ax88179_ethtool_ops; | |
3630 | + dev->net->needed_headroom = 8; | |
3631 | + | |
3632 | + /* Initialize MII structure */ | |
3633 | + dev->mii.dev = dev->net; | |
3634 | + dev->mii.mdio_read = ax88179_mdio_read; | |
3635 | + dev->mii.mdio_write = ax88179_mdio_write; | |
3636 | + dev->mii.phy_id_mask = 0xff; | |
3637 | + dev->mii.reg_num_mask = 0xff; | |
3638 | + dev->mii.phy_id = 0x03; | |
3639 | + dev->mii.supports_gmii = 1; | |
3640 | + | |
3641 | + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | |
3642 | + NETIF_F_RXCSUM; | |
3643 | + | |
3644 | + dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | |
3645 | + NETIF_F_RXCSUM; | |
3646 | + | |
3647 | + /* Enable checksum offload */ | |
3648 | + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | | |
3649 | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; | |
3650 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); | |
3651 | + | |
3652 | + *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | | |
3653 | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; | |
3654 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); | |
3655 | + | |
3656 | + /* Configure RX control register => start operation */ | |
3657 | + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | | |
3658 | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; | |
3659 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); | |
3660 | + | |
3661 | + *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | | |
3662 | + AX_MONITOR_MODE_RWMP; | |
3663 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); | |
3664 | + | |
3665 | + /* Configure default medium type => giga */ | |
3666 | + *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | | |
3667 | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX | | |
3668 | + AX_MEDIUM_GIGAMODE; | |
3669 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3670 | + 2, 2, tmp16); | |
3671 | + | |
3672 | + ax88179_led_setting(dev); | |
3673 | + | |
3674 | + ax179_data->eee_enabled = 0; | |
3675 | + ax179_data->eee_active = 0; | |
3676 | + | |
3677 | + ax88179_disable_eee(dev); | |
3678 | + | |
3679 | + ax88179_ethtool_get_eee(dev, &eee_data); | |
3680 | + eee_data.advertised = 0; | |
3681 | + ax88179_ethtool_set_eee(dev, &eee_data); | |
3682 | + | |
3683 | + /* Restart autoneg */ | |
3684 | + mii_nway_restart(&dev->mii); | |
3685 | + | |
3686 | + usbnet_link_change(dev, 0, 0); | |
3687 | + | |
3688 | + return 0; | |
3689 | +} | |
3690 | + | |
3691 | +static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf) | |
3692 | +{ | |
3693 | + u16 tmp16; | |
3694 | + | |
3695 | + /* Configure RX control register => stop operation */ | |
3696 | + tmp16 = AX_RX_CTL_STOP; | |
3697 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16); | |
3698 | + | |
3699 | + tmp16 = 0; | |
3700 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp16); | |
3701 | + | |
3702 | + /* Power down ethernet PHY */ | |
3703 | + tmp16 = 0; | |
3704 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16); | |
3705 | +} | |
3706 | + | |
3707 | +static void | |
3708 | +ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr) | |
3709 | +{ | |
3710 | + skb->ip_summed = CHECKSUM_NONE; | |
3711 | + | |
3712 | + /* checksum error bit is set */ | |
3713 | + if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) || | |
3714 | + (*pkt_hdr & AX_RXHDR_L4CSUM_ERR)) | |
3715 | + return; | |
3716 | + | |
3717 | + /* It must be a TCP or UDP packet with a valid checksum */ | |
3718 | + if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) || | |
3719 | + ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP)) | |
3720 | + skb->ip_summed = CHECKSUM_UNNECESSARY; | |
3721 | +} | |
3722 | + | |
3723 | +static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
3724 | +{ | |
3725 | + struct sk_buff *ax_skb; | |
3726 | + int pkt_cnt; | |
3727 | + u32 rx_hdr; | |
3728 | + u16 hdr_off; | |
3729 | + u32 *pkt_hdr; | |
3730 | + | |
3731 | + /* This check is no longer done by usbnet */ | |
3732 | + if (skb->len < dev->net->hard_header_len) | |
3733 | + return 0; | |
3734 | + | |
3735 | + skb_trim(skb, skb->len - 4); | |
3736 | + memcpy(&rx_hdr, skb_tail_pointer(skb), 4); | |
3737 | + le32_to_cpus(&rx_hdr); | |
3738 | + | |
3739 | + pkt_cnt = (u16)rx_hdr; | |
3740 | + hdr_off = (u16)(rx_hdr >> 16); | |
3741 | + pkt_hdr = (u32 *)(skb->data + hdr_off); | |
3742 | + | |
3743 | + while (pkt_cnt--) { | |
3744 | + u16 pkt_len; | |
3745 | + | |
3746 | + le32_to_cpus(pkt_hdr); | |
3747 | + pkt_len = (*pkt_hdr >> 16) & 0x1fff; | |
3748 | + | |
3749 | + /* Check CRC or runt packet */ | |
3750 | + if ((*pkt_hdr & AX_RXHDR_CRC_ERR) || | |
3751 | + (*pkt_hdr & AX_RXHDR_DROP_ERR)) { | |
3752 | + skb_pull(skb, (pkt_len + 7) & 0xFFF8); | |
3753 | + pkt_hdr++; | |
3754 | + continue; | |
3755 | + } | |
3756 | + | |
3757 | + if (pkt_cnt == 0) { | |
3758 | + /* Skip IP alignment psudo header */ | |
3759 | + skb_pull(skb, 2); | |
3760 | + skb->len = pkt_len; | |
3761 | + skb_set_tail_pointer(skb, pkt_len); | |
3762 | + skb->truesize = pkt_len + sizeof(struct sk_buff); | |
3763 | + ax88179_rx_checksum(skb, pkt_hdr); | |
3764 | + return 1; | |
3765 | + } | |
3766 | + | |
3767 | + ax_skb = skb_clone(skb, GFP_ATOMIC); | |
3768 | + if (ax_skb) { | |
3769 | + ax_skb->len = pkt_len; | |
3770 | + ax_skb->data = skb->data + 2; | |
3771 | + skb_set_tail_pointer(ax_skb, pkt_len); | |
3772 | + ax_skb->truesize = pkt_len + sizeof(struct sk_buff); | |
3773 | + ax88179_rx_checksum(ax_skb, pkt_hdr); | |
3774 | + usbnet_skb_return(dev, ax_skb); | |
3775 | + } else { | |
3776 | + return 0; | |
3777 | + } | |
3778 | + | |
3779 | + skb_pull(skb, (pkt_len + 7) & 0xFFF8); | |
3780 | + pkt_hdr++; | |
3781 | + } | |
3782 | + return 1; | |
3783 | +} | |
3784 | + | |
3785 | +static struct sk_buff * | |
3786 | +ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |
3787 | +{ | |
3788 | + u32 tx_hdr1, tx_hdr2; | |
3789 | + int frame_size = dev->maxpacket; | |
3790 | + int mss = skb_shinfo(skb)->gso_size; | |
3791 | + int headroom; | |
3792 | + | |
3793 | + tx_hdr1 = skb->len; | |
3794 | + tx_hdr2 = mss; | |
3795 | + if (((skb->len + 8) % frame_size) == 0) | |
3796 | + tx_hdr2 |= 0x80008000; /* Enable padding */ | |
3797 | + | |
3798 | + headroom = skb_headroom(skb) - 8; | |
3799 | + | |
3800 | + if ((skb_header_cloned(skb) || headroom < 0) && | |
3801 | + pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { | |
3802 | + dev_kfree_skb_any(skb); | |
3803 | + return NULL; | |
3804 | + } | |
3805 | + | |
3806 | + skb_push(skb, 4); | |
3807 | + cpu_to_le32s(&tx_hdr2); | |
3808 | + skb_copy_to_linear_data(skb, &tx_hdr2, 4); | |
3809 | + | |
3810 | + skb_push(skb, 4); | |
3811 | + cpu_to_le32s(&tx_hdr1); | |
3812 | + skb_copy_to_linear_data(skb, &tx_hdr1, 4); | |
3813 | + | |
3814 | + return skb; | |
3815 | +} | |
3816 | + | |
3817 | +static int ax88179_link_reset(struct usbnet *dev) | |
3818 | +{ | |
3819 | + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; | |
3820 | + u8 tmp[5], link_sts; | |
3821 | + u16 mode, tmp16, delay = HZ / 10; | |
3822 | + u32 tmp32 = 0x40000000; | |
3823 | + unsigned long jtimeout; | |
3824 | + | |
3825 | + jtimeout = jiffies + delay; | |
3826 | + while (tmp32 & 0x40000000) { | |
3827 | + mode = 0; | |
3828 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode); | |
3829 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, | |
3830 | + &ax179_data->rxctl); | |
3831 | + | |
3832 | + /*link up, check the usb device control TX FIFO full or empty*/ | |
3833 | + ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32); | |
3834 | + | |
3835 | + if (time_after(jiffies, jtimeout)) | |
3836 | + return 0; | |
3837 | + } | |
3838 | + | |
3839 | + mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | | |
3840 | + AX_MEDIUM_RXFLOW_CTRLEN; | |
3841 | + | |
3842 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS, | |
3843 | + 1, 1, &link_sts); | |
3844 | + | |
3845 | + ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, | |
3846 | + GMII_PHY_PHYSR, 2, &tmp16); | |
3847 | + | |
3848 | + if (!(tmp16 & GMII_PHY_PHYSR_LINK)) { | |
3849 | + return 0; | |
3850 | + } else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) { | |
3851 | + mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ; | |
3852 | + if (dev->net->mtu > 1500) | |
3853 | + mode |= AX_MEDIUM_JUMBO_EN; | |
3854 | + | |
3855 | + if (link_sts & AX_USB_SS) | |
3856 | + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); | |
3857 | + else if (link_sts & AX_USB_HS) | |
3858 | + memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5); | |
3859 | + else | |
3860 | + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); | |
3861 | + } else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) { | |
3862 | + mode |= AX_MEDIUM_PS; | |
3863 | + | |
3864 | + if (link_sts & (AX_USB_SS | AX_USB_HS)) | |
3865 | + memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5); | |
3866 | + else | |
3867 | + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); | |
3868 | + } else { | |
3869 | + memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5); | |
3870 | + } | |
3871 | + | |
3872 | + /* RX bulk configuration */ | |
3873 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); | |
3874 | + | |
3875 | + dev->rx_urb_size = (1024 * (tmp[3] + 2)); | |
3876 | + | |
3877 | + if (tmp16 & GMII_PHY_PHYSR_FULL) | |
3878 | + mode |= AX_MEDIUM_FULL_DUPLEX; | |
3879 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3880 | + 2, 2, &mode); | |
3881 | + | |
3882 | + ax179_data->eee_enabled = ax88179_chk_eee(dev); | |
3883 | + | |
3884 | + netif_carrier_on(dev->net); | |
3885 | + | |
3886 | + return 0; | |
3887 | +} | |
3888 | + | |
3889 | +static int ax88179_reset(struct usbnet *dev) | |
3890 | +{ | |
3891 | + u8 buf[5]; | |
3892 | + u16 *tmp16; | |
3893 | + u8 *tmp; | |
3894 | + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; | |
3895 | + struct ethtool_eee eee_data; | |
3896 | + | |
3897 | + tmp16 = (u16 *)buf; | |
3898 | + tmp = (u8 *)buf; | |
3899 | + | |
3900 | + /* Power up ethernet PHY */ | |
3901 | + *tmp16 = 0; | |
3902 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); | |
3903 | + | |
3904 | + *tmp16 = AX_PHYPWR_RSTCTL_IPRL; | |
3905 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16); | |
3906 | + msleep(200); | |
3907 | + | |
3908 | + *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS; | |
3909 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); | |
3910 | + msleep(100); | |
3911 | + | |
3912 | + /* Ethernet PHY Auto Detach*/ | |
3913 | + ax88179_auto_detach(dev, 0); | |
3914 | + | |
3915 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, | |
3916 | + dev->net->dev_addr); | |
3917 | + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); | |
3918 | + | |
3919 | + /* RX bulk configuration */ | |
3920 | + memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); | |
3921 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp); | |
3922 | + | |
3923 | + dev->rx_urb_size = 1024 * 20; | |
3924 | + | |
3925 | + *tmp = 0x34; | |
3926 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp); | |
3927 | + | |
3928 | + *tmp = 0x52; | |
3929 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH, | |
3930 | + 1, 1, tmp); | |
3931 | + | |
3932 | + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | |
3933 | + NETIF_F_RXCSUM; | |
3934 | + | |
3935 | + dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | |
3936 | + NETIF_F_RXCSUM; | |
3937 | + | |
3938 | + /* Enable checksum offload */ | |
3939 | + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | | |
3940 | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6; | |
3941 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp); | |
3942 | + | |
3943 | + *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP | | |
3944 | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6; | |
3945 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp); | |
3946 | + | |
3947 | + /* Configure RX control register => start operation */ | |
3948 | + *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_IPE | AX_RX_CTL_START | | |
3949 | + AX_RX_CTL_AP | AX_RX_CTL_AMALL | AX_RX_CTL_AB; | |
3950 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16); | |
3951 | + | |
3952 | + *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL | | |
3953 | + AX_MONITOR_MODE_RWMP; | |
3954 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MOD, 1, 1, tmp); | |
3955 | + | |
3956 | + /* Configure default medium type => giga */ | |
3957 | + *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN | | |
3958 | + AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX | | |
3959 | + AX_MEDIUM_GIGAMODE; | |
3960 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3961 | + 2, 2, tmp16); | |
3962 | + | |
3963 | + ax88179_led_setting(dev); | |
3964 | + | |
3965 | + ax179_data->eee_enabled = 0; | |
3966 | + ax179_data->eee_active = 0; | |
3967 | + | |
3968 | + ax88179_disable_eee(dev); | |
3969 | + | |
3970 | + ax88179_ethtool_get_eee(dev, &eee_data); | |
3971 | + eee_data.advertised = 0; | |
3972 | + ax88179_ethtool_set_eee(dev, &eee_data); | |
3973 | + | |
3974 | + /* Restart autoneg */ | |
3975 | + mii_nway_restart(&dev->mii); | |
3976 | + | |
3977 | + usbnet_link_change(dev, 0, 0); | |
3978 | + | |
3979 | + return 0; | |
3980 | +} | |
3981 | + | |
3982 | +static int ax88179_stop(struct usbnet *dev) | |
3983 | +{ | |
3984 | + u16 tmp16; | |
3985 | + | |
3986 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3987 | + 2, 2, &tmp16); | |
3988 | + tmp16 &= ~AX_MEDIUM_RECEIVE_EN; | |
3989 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, | |
3990 | + 2, 2, &tmp16); | |
3991 | + | |
3992 | + return 0; | |
3993 | +} | |
3994 | + | |
3995 | +static const struct driver_info ax88179_info = { | |
3996 | + .description = "ASIX AX88179 USB 3.0 Gigabit Ethernet", | |
3997 | + .bind = ax88179_bind, | |
3998 | + .unbind = ax88179_unbind, | |
3999 | + .status = ax88179_status, | |
4000 | + .link_reset = ax88179_link_reset, | |
4001 | + .reset = ax88179_reset, | |
4002 | + .stop = ax88179_stop, | |
4003 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4004 | + .rx_fixup = ax88179_rx_fixup, | |
4005 | + .tx_fixup = ax88179_tx_fixup, | |
4006 | +}; | |
4007 | + | |
4008 | +static const struct driver_info ax88178a_info = { | |
4009 | + .description = "ASIX AX88178A USB 2.0 Gigabit Ethernet", | |
4010 | + .bind = ax88179_bind, | |
4011 | + .unbind = ax88179_unbind, | |
4012 | + .status = ax88179_status, | |
4013 | + .link_reset = ax88179_link_reset, | |
4014 | + .reset = ax88179_reset, | |
4015 | + .stop = ax88179_stop, | |
4016 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4017 | + .rx_fixup = ax88179_rx_fixup, | |
4018 | + .tx_fixup = ax88179_tx_fixup, | |
4019 | +}; | |
4020 | + | |
4021 | +static const struct driver_info dlink_dub1312_info = { | |
4022 | + .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter", | |
4023 | + .bind = ax88179_bind, | |
4024 | + .unbind = ax88179_unbind, | |
4025 | + .status = ax88179_status, | |
4026 | + .link_reset = ax88179_link_reset, | |
4027 | + .reset = ax88179_reset, | |
4028 | + .stop = ax88179_stop, | |
4029 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4030 | + .rx_fixup = ax88179_rx_fixup, | |
4031 | + .tx_fixup = ax88179_tx_fixup, | |
4032 | +}; | |
4033 | + | |
4034 | +static const struct driver_info sitecom_info = { | |
4035 | + .description = "Sitecom USB 3.0 to Gigabit Adapter", | |
4036 | + .bind = ax88179_bind, | |
4037 | + .unbind = ax88179_unbind, | |
4038 | + .status = ax88179_status, | |
4039 | + .link_reset = ax88179_link_reset, | |
4040 | + .reset = ax88179_reset, | |
4041 | + .stop = ax88179_stop, | |
4042 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4043 | + .rx_fixup = ax88179_rx_fixup, | |
4044 | + .tx_fixup = ax88179_tx_fixup, | |
4045 | +}; | |
4046 | + | |
4047 | +static const struct driver_info samsung_info = { | |
4048 | + .description = "Samsung USB Ethernet Adapter", | |
4049 | + .bind = ax88179_bind, | |
4050 | + .unbind = ax88179_unbind, | |
4051 | + .status = ax88179_status, | |
4052 | + .link_reset = ax88179_link_reset, | |
4053 | + .reset = ax88179_reset, | |
4054 | + .stop = ax88179_stop, | |
4055 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4056 | + .rx_fixup = ax88179_rx_fixup, | |
4057 | + .tx_fixup = ax88179_tx_fixup, | |
4058 | +}; | |
4059 | + | |
4060 | +static const struct driver_info lenovo_info = { | |
4061 | + .description = "Lenovo OneLinkDock Gigabit LAN", | |
4062 | + .bind = ax88179_bind, | |
4063 | + .unbind = ax88179_unbind, | |
4064 | + .status = ax88179_status, | |
4065 | + .link_reset = ax88179_link_reset, | |
4066 | + .reset = ax88179_reset, | |
4067 | + .stop = ax88179_stop, | |
4068 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, | |
4069 | + .rx_fixup = ax88179_rx_fixup, | |
4070 | + .tx_fixup = ax88179_tx_fixup, | |
4071 | +}; | |
4072 | + | |
4073 | +static const struct usb_device_id products[] = { | |
4074 | +{ | |
4075 | + /* ASIX AX88179 10/100/1000 */ | |
4076 | + USB_DEVICE(0x0b95, 0x1790), | |
4077 | + .driver_info = (unsigned long)&ax88179_info, | |
4078 | +}, { | |
4079 | + /* ASIX AX88178A 10/100/1000 */ | |
4080 | + USB_DEVICE(0x0b95, 0x178a), | |
4081 | + .driver_info = (unsigned long)&ax88178a_info, | |
4082 | +}, { | |
4083 | + /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */ | |
4084 | + USB_DEVICE(0x2001, 0x4a00), | |
4085 | + .driver_info = (unsigned long)&dlink_dub1312_info, | |
4086 | +}, { | |
4087 | + /* Sitecom USB 3.0 to Gigabit Adapter */ | |
4088 | + USB_DEVICE(0x0df6, 0x0072), | |
4089 | + .driver_info = (unsigned long)&sitecom_info, | |
4090 | +}, { | |
4091 | + /* Samsung USB Ethernet Adapter */ | |
4092 | + USB_DEVICE(0x04e8, 0xa100), | |
4093 | + .driver_info = (unsigned long)&samsung_info, | |
4094 | +}, { | |
4095 | + /* Lenovo OneLinkDock Gigabit LAN */ | |
4096 | + USB_DEVICE(0x17ef, 0x304b), | |
4097 | + .driver_info = (unsigned long)&lenovo_info, | |
4098 | +}, | |
4099 | + { }, | |
4100 | +}; | |
4101 | +MODULE_DEVICE_TABLE(usb, products); | |
4102 | + | |
4103 | +static struct usb_driver ax88179_178a_driver = { | |
4104 | + .name = "ax88179_178a", | |
4105 | + .id_table = products, | |
4106 | + .probe = usbnet_probe, | |
4107 | + .suspend = ax88179_suspend, | |
4108 | + .resume = ax88179_resume, | |
4109 | + .reset_resume = ax88179_resume, | |
4110 | + .disconnect = usbnet_disconnect, | |
4111 | + .supports_autosuspend = 1, | |
4112 | + .disable_hub_initiated_lpm = 1, | |
4113 | +}; | |
4114 | + | |
4115 | +module_usb_driver(ax88179_178a_driver); | |
4116 | + | |
4117 | +MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices"); | |
4118 | +MODULE_LICENSE("GPL"); | |
4119 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/catc.c backports-3.18.1-1/drivers/net/usb/catc.c | |
4120 | --- backports-3.18.1-1.org/drivers/net/usb/catc.c 1970-01-01 01:00:00.000000000 +0100 | |
4121 | +++ backports-3.18.1-1/drivers/net/usb/catc.c 2014-12-16 18:39:45.000000000 +0100 | |
4122 | @@ -0,0 +1,965 @@ | |
4123 | +/* | |
4124 | + * Copyright (c) 2001 Vojtech Pavlik | |
4125 | + * | |
4126 | + * CATC EL1210A NetMate USB Ethernet driver | |
4127 | + * | |
4128 | + * Sponsored by SuSE | |
4129 | + * | |
4130 | + * Based on the work of | |
4131 | + * Donald Becker | |
4132 | + * | |
4133 | + * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002 | |
4134 | + * - adds support for Belkin F5U011 | |
4135 | + */ | |
4136 | + | |
4137 | +/* | |
4138 | + * This program is free software; you can redistribute it and/or modify | |
4139 | + * it under the terms of the GNU General Public License as published by | |
4140 | + * the Free Software Foundation; either version 2 of the License, or | |
4141 | + * (at your option) any later version. | |
4142 | + * | |
4143 | + * This program is distributed in the hope that it will be useful, | |
4144 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
4145 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
4146 | + * GNU General Public License for more details. | |
4147 | + * | |
4148 | + * You should have received a copy of the GNU General Public License | |
4149 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
4150 | + * | |
4151 | + * Should you need to contact me, the author, you can do so either by | |
4152 | + * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
4153 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
4154 | + */ | |
4155 | + | |
4156 | +#include <linux/module.h> | |
4157 | +#include <linux/kernel.h> | |
4158 | +#include <linux/string.h> | |
4159 | +#include <linux/netdevice.h> | |
4160 | +#include <linux/etherdevice.h> | |
4161 | +#include <linux/skbuff.h> | |
4162 | +#include <linux/spinlock.h> | |
4163 | +#include <linux/ethtool.h> | |
4164 | +#include <linux/crc32.h> | |
4165 | +#include <linux/bitops.h> | |
4166 | +#include <linux/gfp.h> | |
4167 | +#include <asm/uaccess.h> | |
4168 | + | |
4169 | +#undef DEBUG | |
4170 | + | |
4171 | +#include <linux/usb.h> | |
4172 | + | |
4173 | +/* | |
4174 | + * Version information. | |
4175 | + */ | |
4176 | + | |
4177 | +#define DRIVER_VERSION "v2.8" | |
4178 | +#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@suse.cz>" | |
4179 | +#define DRIVER_DESC "CATC EL1210A NetMate USB Ethernet driver" | |
4180 | +#define SHORT_DRIVER_DESC "EL1210A NetMate USB Ethernet" | |
4181 | + | |
4182 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
4183 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
4184 | +MODULE_LICENSE("GPL"); | |
4185 | + | |
4186 | +static const char driver_name[] = "catc"; | |
4187 | + | |
4188 | +/* | |
4189 | + * Some defines. | |
4190 | + */ | |
4191 | + | |
4192 | +#define STATS_UPDATE (HZ) /* Time between stats updates */ | |
4193 | +#define TX_TIMEOUT (5*HZ) /* Max time the queue can be stopped */ | |
4194 | +#define PKT_SZ 1536 /* Max Ethernet packet size */ | |
4195 | +#define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */ | |
4196 | +#define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */ | |
4197 | +#define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */ | |
4198 | +#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */ | |
4199 | + | |
4200 | +/* | |
4201 | + * Control requests. | |
4202 | + */ | |
4203 | + | |
4204 | +enum control_requests { | |
4205 | + ReadMem = 0xf1, | |
4206 | + GetMac = 0xf2, | |
4207 | + Reset = 0xf4, | |
4208 | + SetMac = 0xf5, | |
4209 | + SetRxMode = 0xf5, /* F5U011 only */ | |
4210 | + WriteROM = 0xf8, | |
4211 | + SetReg = 0xfa, | |
4212 | + GetReg = 0xfb, | |
4213 | + WriteMem = 0xfc, | |
4214 | + ReadROM = 0xfd, | |
4215 | +}; | |
4216 | + | |
4217 | +/* | |
4218 | + * Registers. | |
4219 | + */ | |
4220 | + | |
4221 | +enum register_offsets { | |
4222 | + TxBufCount = 0x20, | |
4223 | + RxBufCount = 0x21, | |
4224 | + OpModes = 0x22, | |
4225 | + TxQed = 0x23, | |
4226 | + RxQed = 0x24, | |
4227 | + MaxBurst = 0x25, | |
4228 | + RxUnit = 0x60, | |
4229 | + EthStatus = 0x61, | |
4230 | + StationAddr0 = 0x67, | |
4231 | + EthStats = 0x69, | |
4232 | + LEDCtrl = 0x81, | |
4233 | +}; | |
4234 | + | |
4235 | +enum eth_stats { | |
4236 | + TxSingleColl = 0x00, | |
4237 | + TxMultiColl = 0x02, | |
4238 | + TxExcessColl = 0x04, | |
4239 | + RxFramErr = 0x06, | |
4240 | +}; | |
4241 | + | |
4242 | +enum op_mode_bits { | |
4243 | + Op3MemWaits = 0x03, | |
4244 | + OpLenInclude = 0x08, | |
4245 | + OpRxMerge = 0x10, | |
4246 | + OpTxMerge = 0x20, | |
4247 | + OpWin95bugfix = 0x40, | |
4248 | + OpLoopback = 0x80, | |
4249 | +}; | |
4250 | + | |
4251 | +enum rx_filter_bits { | |
4252 | + RxEnable = 0x01, | |
4253 | + RxPolarity = 0x02, | |
4254 | + RxForceOK = 0x04, | |
4255 | + RxMultiCast = 0x08, | |
4256 | + RxPromisc = 0x10, | |
4257 | + AltRxPromisc = 0x20, /* F5U011 uses different bit */ | |
4258 | +}; | |
4259 | + | |
4260 | +enum led_values { | |
4261 | + LEDFast = 0x01, | |
4262 | + LEDSlow = 0x02, | |
4263 | + LEDFlash = 0x03, | |
4264 | + LEDPulse = 0x04, | |
4265 | + LEDLink = 0x08, | |
4266 | +}; | |
4267 | + | |
4268 | +enum link_status { | |
4269 | + LinkNoChange = 0, | |
4270 | + LinkGood = 1, | |
4271 | + LinkBad = 2 | |
4272 | +}; | |
4273 | + | |
4274 | +/* | |
4275 | + * The catc struct. | |
4276 | + */ | |
4277 | + | |
4278 | +#define CTRL_RUNNING 0 | |
4279 | +#define RX_RUNNING 1 | |
4280 | +#define TX_RUNNING 2 | |
4281 | + | |
4282 | +struct catc { | |
4283 | + struct net_device *netdev; | |
4284 | + struct usb_device *usbdev; | |
4285 | + | |
4286 | + unsigned long flags; | |
4287 | + | |
4288 | + unsigned int tx_ptr, tx_idx; | |
4289 | + unsigned int ctrl_head, ctrl_tail; | |
4290 | + spinlock_t tx_lock, ctrl_lock; | |
4291 | + | |
4292 | + u8 tx_buf[2][TX_MAX_BURST * (PKT_SZ + 2)]; | |
4293 | + u8 rx_buf[RX_MAX_BURST * (PKT_SZ + 2)]; | |
4294 | + u8 irq_buf[2]; | |
4295 | + u8 ctrl_buf[64]; | |
4296 | + struct usb_ctrlrequest ctrl_dr; | |
4297 | + | |
4298 | + struct timer_list timer; | |
4299 | + u8 stats_buf[8]; | |
4300 | + u16 stats_vals[4]; | |
4301 | + unsigned long last_stats; | |
4302 | + | |
4303 | + u8 multicast[64]; | |
4304 | + | |
4305 | + struct ctrl_queue { | |
4306 | + u8 dir; | |
4307 | + u8 request; | |
4308 | + u16 value; | |
4309 | + u16 index; | |
4310 | + void *buf; | |
4311 | + int len; | |
4312 | + void (*callback)(struct catc *catc, struct ctrl_queue *q); | |
4313 | + } ctrl_queue[CTRL_QUEUE]; | |
4314 | + | |
4315 | + struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb; | |
4316 | + | |
4317 | + u8 is_f5u011; /* Set if device is an F5U011 */ | |
4318 | + u8 rxmode[2]; /* Used for F5U011 */ | |
4319 | + atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */ | |
4320 | +}; | |
4321 | + | |
4322 | +/* | |
4323 | + * Useful macros. | |
4324 | + */ | |
4325 | + | |
4326 | +#define catc_get_mac(catc, mac) catc_ctrl_msg(catc, USB_DIR_IN, GetMac, 0, 0, mac, 6) | |
4327 | +#define catc_reset(catc) catc_ctrl_msg(catc, USB_DIR_OUT, Reset, 0, 0, NULL, 0) | |
4328 | +#define catc_set_reg(catc, reg, val) catc_ctrl_msg(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0) | |
4329 | +#define catc_get_reg(catc, reg, buf) catc_ctrl_msg(catc, USB_DIR_IN, GetReg, 0, reg, buf, 1) | |
4330 | +#define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size) | |
4331 | +#define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size) | |
4332 | + | |
4333 | +#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2) | |
4334 | +#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL) | |
4335 | +#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL) | |
4336 | + | |
4337 | +#define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL) | |
4338 | +#define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb) | |
4339 | +#define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL) | |
4340 | + | |
4341 | +/* | |
4342 | + * Receive routines. | |
4343 | + */ | |
4344 | + | |
4345 | +static void catc_rx_done(struct urb *urb) | |
4346 | +{ | |
4347 | + struct catc *catc = urb->context; | |
4348 | + u8 *pkt_start = urb->transfer_buffer; | |
4349 | + struct sk_buff *skb; | |
4350 | + int pkt_len, pkt_offset = 0; | |
4351 | + int status = urb->status; | |
4352 | + | |
4353 | + if (!catc->is_f5u011) { | |
4354 | + clear_bit(RX_RUNNING, &catc->flags); | |
4355 | + pkt_offset = 2; | |
4356 | + } | |
4357 | + | |
4358 | + if (status) { | |
4359 | + dev_dbg(&urb->dev->dev, "rx_done, status %d, length %d\n", | |
4360 | + status, urb->actual_length); | |
4361 | + return; | |
4362 | + } | |
4363 | + | |
4364 | + do { | |
4365 | + if(!catc->is_f5u011) { | |
4366 | + pkt_len = le16_to_cpup((__le16*)pkt_start); | |
4367 | + if (pkt_len > urb->actual_length) { | |
4368 | + catc->netdev->stats.rx_length_errors++; | |
4369 | + catc->netdev->stats.rx_errors++; | |
4370 | + break; | |
4371 | + } | |
4372 | + } else { | |
4373 | + pkt_len = urb->actual_length; | |
4374 | + } | |
4375 | + | |
4376 | + if (!(skb = dev_alloc_skb(pkt_len))) | |
4377 | + return; | |
4378 | + | |
4379 | + skb_copy_to_linear_data(skb, pkt_start + pkt_offset, pkt_len); | |
4380 | + skb_put(skb, pkt_len); | |
4381 | + | |
4382 | + skb->protocol = eth_type_trans(skb, catc->netdev); | |
4383 | + netif_rx(skb); | |
4384 | + | |
4385 | + catc->netdev->stats.rx_packets++; | |
4386 | + catc->netdev->stats.rx_bytes += pkt_len; | |
4387 | + | |
4388 | + /* F5U011 only does one packet per RX */ | |
4389 | + if (catc->is_f5u011) | |
4390 | + break; | |
4391 | + pkt_start += (((pkt_len + 1) >> 6) + 1) << 6; | |
4392 | + | |
4393 | + } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); | |
4394 | + | |
4395 | + if (catc->is_f5u011) { | |
4396 | + if (atomic_read(&catc->recq_sz)) { | |
4397 | + int state; | |
4398 | + atomic_dec(&catc->recq_sz); | |
4399 | + netdev_dbg(catc->netdev, "getting extra packet\n"); | |
4400 | + urb->dev = catc->usbdev; | |
4401 | + if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { | |
4402 | + netdev_dbg(catc->netdev, | |
4403 | + "submit(rx_urb) status %d\n", state); | |
4404 | + } | |
4405 | + } else { | |
4406 | + clear_bit(RX_RUNNING, &catc->flags); | |
4407 | + } | |
4408 | + } | |
4409 | +} | |
4410 | + | |
4411 | +static void catc_irq_done(struct urb *urb) | |
4412 | +{ | |
4413 | + struct catc *catc = urb->context; | |
4414 | + u8 *data = urb->transfer_buffer; | |
4415 | + int status = urb->status; | |
4416 | + unsigned int hasdata = 0, linksts = LinkNoChange; | |
4417 | + int res; | |
4418 | + | |
4419 | + if (!catc->is_f5u011) { | |
4420 | + hasdata = data[1] & 0x80; | |
4421 | + if (data[1] & 0x40) | |
4422 | + linksts = LinkGood; | |
4423 | + else if (data[1] & 0x20) | |
4424 | + linksts = LinkBad; | |
4425 | + } else { | |
4426 | + hasdata = (unsigned int)(be16_to_cpup((__be16*)data) & 0x0fff); | |
4427 | + if (data[0] == 0x90) | |
4428 | + linksts = LinkGood; | |
4429 | + else if (data[0] == 0xA0) | |
4430 | + linksts = LinkBad; | |
4431 | + } | |
4432 | + | |
4433 | + switch (status) { | |
4434 | + case 0: /* success */ | |
4435 | + break; | |
4436 | + case -ECONNRESET: /* unlink */ | |
4437 | + case -ENOENT: | |
4438 | + case -ESHUTDOWN: | |
4439 | + return; | |
4440 | + /* -EPIPE: should clear the halt */ | |
4441 | + default: /* error */ | |
4442 | + dev_dbg(&urb->dev->dev, | |
4443 | + "irq_done, status %d, data %02x %02x.\n", | |
4444 | + status, data[0], data[1]); | |
4445 | + goto resubmit; | |
4446 | + } | |
4447 | + | |
4448 | + if (linksts == LinkGood) { | |
4449 | + netif_carrier_on(catc->netdev); | |
4450 | + netdev_dbg(catc->netdev, "link ok\n"); | |
4451 | + } | |
4452 | + | |
4453 | + if (linksts == LinkBad) { | |
4454 | + netif_carrier_off(catc->netdev); | |
4455 | + netdev_dbg(catc->netdev, "link bad\n"); | |
4456 | + } | |
4457 | + | |
4458 | + if (hasdata) { | |
4459 | + if (test_and_set_bit(RX_RUNNING, &catc->flags)) { | |
4460 | + if (catc->is_f5u011) | |
4461 | + atomic_inc(&catc->recq_sz); | |
4462 | + } else { | |
4463 | + catc->rx_urb->dev = catc->usbdev; | |
4464 | + if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { | |
4465 | + dev_err(&catc->usbdev->dev, | |
4466 | + "submit(rx_urb) status %d\n", res); | |
4467 | + } | |
4468 | + } | |
4469 | + } | |
4470 | +resubmit: | |
4471 | + res = usb_submit_urb (urb, GFP_ATOMIC); | |
4472 | + if (res) | |
4473 | + dev_err(&catc->usbdev->dev, | |
4474 | + "can't resubmit intr, %s-%s, status %d\n", | |
4475 | + catc->usbdev->bus->bus_name, | |
4476 | + catc->usbdev->devpath, res); | |
4477 | +} | |
4478 | + | |
4479 | +/* | |
4480 | + * Transmit routines. | |
4481 | + */ | |
4482 | + | |
4483 | +static int catc_tx_run(struct catc *catc) | |
4484 | +{ | |
4485 | + int status; | |
4486 | + | |
4487 | + if (catc->is_f5u011) | |
4488 | + catc->tx_ptr = (catc->tx_ptr + 63) & ~63; | |
4489 | + | |
4490 | + catc->tx_urb->transfer_buffer_length = catc->tx_ptr; | |
4491 | + catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx]; | |
4492 | + catc->tx_urb->dev = catc->usbdev; | |
4493 | + | |
4494 | + if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0) | |
4495 | + dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n", | |
4496 | + status); | |
4497 | + | |
4498 | + catc->tx_idx = !catc->tx_idx; | |
4499 | + catc->tx_ptr = 0; | |
4500 | + | |
4501 | + catc->netdev->trans_start = jiffies; | |
4502 | + return status; | |
4503 | +} | |
4504 | + | |
4505 | +static void catc_tx_done(struct urb *urb) | |
4506 | +{ | |
4507 | + struct catc *catc = urb->context; | |
4508 | + unsigned long flags; | |
4509 | + int r, status = urb->status; | |
4510 | + | |
4511 | + if (status == -ECONNRESET) { | |
4512 | + dev_dbg(&urb->dev->dev, "Tx Reset.\n"); | |
4513 | + urb->status = 0; | |
4514 | + catc->netdev->trans_start = jiffies; | |
4515 | + catc->netdev->stats.tx_errors++; | |
4516 | + clear_bit(TX_RUNNING, &catc->flags); | |
4517 | + netif_wake_queue(catc->netdev); | |
4518 | + return; | |
4519 | + } | |
4520 | + | |
4521 | + if (status) { | |
4522 | + dev_dbg(&urb->dev->dev, "tx_done, status %d, length %d\n", | |
4523 | + status, urb->actual_length); | |
4524 | + return; | |
4525 | + } | |
4526 | + | |
4527 | + spin_lock_irqsave(&catc->tx_lock, flags); | |
4528 | + | |
4529 | + if (catc->tx_ptr) { | |
4530 | + r = catc_tx_run(catc); | |
4531 | + if (unlikely(r < 0)) | |
4532 | + clear_bit(TX_RUNNING, &catc->flags); | |
4533 | + } else { | |
4534 | + clear_bit(TX_RUNNING, &catc->flags); | |
4535 | + } | |
4536 | + | |
4537 | + netif_wake_queue(catc->netdev); | |
4538 | + | |
4539 | + spin_unlock_irqrestore(&catc->tx_lock, flags); | |
4540 | +} | |
4541 | + | |
4542 | +static netdev_tx_t catc_start_xmit(struct sk_buff *skb, | |
4543 | + struct net_device *netdev) | |
4544 | +{ | |
4545 | + struct catc *catc = netdev_priv(netdev); | |
4546 | + unsigned long flags; | |
4547 | + int r = 0; | |
4548 | + char *tx_buf; | |
4549 | + | |
4550 | + spin_lock_irqsave(&catc->tx_lock, flags); | |
4551 | + | |
4552 | + catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; | |
4553 | + tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; | |
4554 | + if (catc->is_f5u011) | |
4555 | + *(__be16 *)tx_buf = cpu_to_be16(skb->len); | |
4556 | + else | |
4557 | + *(__le16 *)tx_buf = cpu_to_le16(skb->len); | |
4558 | + skb_copy_from_linear_data(skb, tx_buf + 2, skb->len); | |
4559 | + catc->tx_ptr += skb->len + 2; | |
4560 | + | |
4561 | + if (!test_and_set_bit(TX_RUNNING, &catc->flags)) { | |
4562 | + r = catc_tx_run(catc); | |
4563 | + if (r < 0) | |
4564 | + clear_bit(TX_RUNNING, &catc->flags); | |
4565 | + } | |
4566 | + | |
4567 | + if ((catc->is_f5u011 && catc->tx_ptr) || | |
4568 | + (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) | |
4569 | + netif_stop_queue(netdev); | |
4570 | + | |
4571 | + spin_unlock_irqrestore(&catc->tx_lock, flags); | |
4572 | + | |
4573 | + if (r >= 0) { | |
4574 | + catc->netdev->stats.tx_bytes += skb->len; | |
4575 | + catc->netdev->stats.tx_packets++; | |
4576 | + } | |
4577 | + | |
4578 | + dev_kfree_skb(skb); | |
4579 | + | |
4580 | + return NETDEV_TX_OK; | |
4581 | +} | |
4582 | + | |
4583 | +static void catc_tx_timeout(struct net_device *netdev) | |
4584 | +{ | |
4585 | + struct catc *catc = netdev_priv(netdev); | |
4586 | + | |
4587 | + dev_warn(&netdev->dev, "Transmit timed out.\n"); | |
4588 | + usb_unlink_urb(catc->tx_urb); | |
4589 | +} | |
4590 | + | |
4591 | +/* | |
4592 | + * Control messages. | |
4593 | + */ | |
4594 | + | |
4595 | +static int catc_ctrl_msg(struct catc *catc, u8 dir, u8 request, u16 value, u16 index, void *buf, int len) | |
4596 | +{ | |
4597 | + int retval = usb_control_msg(catc->usbdev, | |
4598 | + dir ? usb_rcvctrlpipe(catc->usbdev, 0) : usb_sndctrlpipe(catc->usbdev, 0), | |
4599 | + request, 0x40 | dir, value, index, buf, len, 1000); | |
4600 | + return retval < 0 ? retval : 0; | |
4601 | +} | |
4602 | + | |
4603 | +static void catc_ctrl_run(struct catc *catc) | |
4604 | +{ | |
4605 | + struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail; | |
4606 | + struct usb_device *usbdev = catc->usbdev; | |
4607 | + struct urb *urb = catc->ctrl_urb; | |
4608 | + struct usb_ctrlrequest *dr = &catc->ctrl_dr; | |
4609 | + int status; | |
4610 | + | |
4611 | + dr->bRequest = q->request; | |
4612 | + dr->bRequestType = 0x40 | q->dir; | |
4613 | + dr->wValue = cpu_to_le16(q->value); | |
4614 | + dr->wIndex = cpu_to_le16(q->index); | |
4615 | + dr->wLength = cpu_to_le16(q->len); | |
4616 | + | |
4617 | + urb->pipe = q->dir ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0); | |
4618 | + urb->transfer_buffer_length = q->len; | |
4619 | + urb->transfer_buffer = catc->ctrl_buf; | |
4620 | + urb->setup_packet = (void *) dr; | |
4621 | + urb->dev = usbdev; | |
4622 | + | |
4623 | + if (!q->dir && q->buf && q->len) | |
4624 | + memcpy(catc->ctrl_buf, q->buf, q->len); | |
4625 | + | |
4626 | + if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC))) | |
4627 | + dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n", | |
4628 | + status); | |
4629 | +} | |
4630 | + | |
4631 | +static void catc_ctrl_done(struct urb *urb) | |
4632 | +{ | |
4633 | + struct catc *catc = urb->context; | |
4634 | + struct ctrl_queue *q; | |
4635 | + unsigned long flags; | |
4636 | + int status = urb->status; | |
4637 | + | |
4638 | + if (status) | |
4639 | + dev_dbg(&urb->dev->dev, "ctrl_done, status %d, len %d.\n", | |
4640 | + status, urb->actual_length); | |
4641 | + | |
4642 | + spin_lock_irqsave(&catc->ctrl_lock, flags); | |
4643 | + | |
4644 | + q = catc->ctrl_queue + catc->ctrl_tail; | |
4645 | + | |
4646 | + if (q->dir) { | |
4647 | + if (q->buf && q->len) | |
4648 | + memcpy(q->buf, catc->ctrl_buf, q->len); | |
4649 | + else | |
4650 | + q->buf = catc->ctrl_buf; | |
4651 | + } | |
4652 | + | |
4653 | + if (q->callback) | |
4654 | + q->callback(catc, q); | |
4655 | + | |
4656 | + catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); | |
4657 | + | |
4658 | + if (catc->ctrl_head != catc->ctrl_tail) | |
4659 | + catc_ctrl_run(catc); | |
4660 | + else | |
4661 | + clear_bit(CTRL_RUNNING, &catc->flags); | |
4662 | + | |
4663 | + spin_unlock_irqrestore(&catc->ctrl_lock, flags); | |
4664 | +} | |
4665 | + | |
4666 | +static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, | |
4667 | + u16 index, void *buf, int len, void (*callback)(struct catc *catc, struct ctrl_queue *q)) | |
4668 | +{ | |
4669 | + struct ctrl_queue *q; | |
4670 | + int retval = 0; | |
4671 | + unsigned long flags; | |
4672 | + | |
4673 | + spin_lock_irqsave(&catc->ctrl_lock, flags); | |
4674 | + | |
4675 | + q = catc->ctrl_queue + catc->ctrl_head; | |
4676 | + | |
4677 | + q->dir = dir; | |
4678 | + q->request = request; | |
4679 | + q->value = value; | |
4680 | + q->index = index; | |
4681 | + q->buf = buf; | |
4682 | + q->len = len; | |
4683 | + q->callback = callback; | |
4684 | + | |
4685 | + catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); | |
4686 | + | |
4687 | + if (catc->ctrl_head == catc->ctrl_tail) { | |
4688 | + dev_err(&catc->usbdev->dev, "ctrl queue full\n"); | |
4689 | + catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); | |
4690 | + retval = -1; | |
4691 | + } | |
4692 | + | |
4693 | + if (!test_and_set_bit(CTRL_RUNNING, &catc->flags)) | |
4694 | + catc_ctrl_run(catc); | |
4695 | + | |
4696 | + spin_unlock_irqrestore(&catc->ctrl_lock, flags); | |
4697 | + | |
4698 | + return retval; | |
4699 | +} | |
4700 | + | |
4701 | +/* | |
4702 | + * Statistics. | |
4703 | + */ | |
4704 | + | |
4705 | +static void catc_stats_done(struct catc *catc, struct ctrl_queue *q) | |
4706 | +{ | |
4707 | + int index = q->index - EthStats; | |
4708 | + u16 data, last; | |
4709 | + | |
4710 | + catc->stats_buf[index] = *((char *)q->buf); | |
4711 | + | |
4712 | + if (index & 1) | |
4713 | + return; | |
4714 | + | |
4715 | + data = ((u16)catc->stats_buf[index] << 8) | catc->stats_buf[index + 1]; | |
4716 | + last = catc->stats_vals[index >> 1]; | |
4717 | + | |
4718 | + switch (index) { | |
4719 | + case TxSingleColl: | |
4720 | + case TxMultiColl: | |
4721 | + catc->netdev->stats.collisions += data - last; | |
4722 | + break; | |
4723 | + case TxExcessColl: | |
4724 | + catc->netdev->stats.tx_aborted_errors += data - last; | |
4725 | + catc->netdev->stats.tx_errors += data - last; | |
4726 | + break; | |
4727 | + case RxFramErr: | |
4728 | + catc->netdev->stats.rx_frame_errors += data - last; | |
4729 | + catc->netdev->stats.rx_errors += data - last; | |
4730 | + break; | |
4731 | + } | |
4732 | + | |
4733 | + catc->stats_vals[index >> 1] = data; | |
4734 | +} | |
4735 | + | |
4736 | +static void catc_stats_timer(unsigned long data) | |
4737 | +{ | |
4738 | + struct catc *catc = (void *) data; | |
4739 | + int i; | |
4740 | + | |
4741 | + for (i = 0; i < 8; i++) | |
4742 | + catc_get_reg_async(catc, EthStats + 7 - i, catc_stats_done); | |
4743 | + | |
4744 | + mod_timer(&catc->timer, jiffies + STATS_UPDATE); | |
4745 | +} | |
4746 | + | |
4747 | +/* | |
4748 | + * Receive modes. Broadcast, Multicast, Promisc. | |
4749 | + */ | |
4750 | + | |
4751 | +static void catc_multicast(unsigned char *addr, u8 *multicast) | |
4752 | +{ | |
4753 | + u32 crc; | |
4754 | + | |
4755 | + crc = ether_crc_le(6, addr); | |
4756 | + multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); | |
4757 | +} | |
4758 | + | |
4759 | +static void catc_set_multicast_list(struct net_device *netdev) | |
4760 | +{ | |
4761 | + struct catc *catc = netdev_priv(netdev); | |
4762 | + struct netdev_hw_addr *ha; | |
4763 | + u8 broadcast[ETH_ALEN]; | |
4764 | + u8 rx = RxEnable | RxPolarity | RxMultiCast; | |
4765 | + | |
4766 | + memset(broadcast, 0xff, ETH_ALEN); | |
4767 | + memset(catc->multicast, 0, 64); | |
4768 | + | |
4769 | + catc_multicast(broadcast, catc->multicast); | |
4770 | + catc_multicast(netdev->dev_addr, catc->multicast); | |
4771 | + | |
4772 | + if (netdev->flags & IFF_PROMISC) { | |
4773 | + memset(catc->multicast, 0xff, 64); | |
4774 | + rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; | |
4775 | + } | |
4776 | + | |
4777 | + if (netdev->flags & IFF_ALLMULTI) { | |
4778 | + memset(catc->multicast, 0xff, 64); | |
4779 | + } else { | |
4780 | + netdev_for_each_mc_addr(ha, netdev) { | |
4781 | + u32 crc = ether_crc_le(6, ha->addr); | |
4782 | + if (!catc->is_f5u011) { | |
4783 | + catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); | |
4784 | + } else { | |
4785 | + catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); | |
4786 | + } | |
4787 | + } | |
4788 | + } | |
4789 | + if (!catc->is_f5u011) { | |
4790 | + catc_set_reg_async(catc, RxUnit, rx); | |
4791 | + catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); | |
4792 | + } else { | |
4793 | + f5u011_mchash_async(catc, catc->multicast); | |
4794 | + if (catc->rxmode[0] != rx) { | |
4795 | + catc->rxmode[0] = rx; | |
4796 | + netdev_dbg(catc->netdev, | |
4797 | + "Setting RX mode to %2.2X %2.2X\n", | |
4798 | + catc->rxmode[0], catc->rxmode[1]); | |
4799 | + f5u011_rxmode_async(catc, catc->rxmode); | |
4800 | + } | |
4801 | + } | |
4802 | +} | |
4803 | + | |
4804 | +static void catc_get_drvinfo(struct net_device *dev, | |
4805 | + struct ethtool_drvinfo *info) | |
4806 | +{ | |
4807 | + struct catc *catc = netdev_priv(dev); | |
4808 | + strlcpy(info->driver, driver_name, sizeof(info->driver)); | |
4809 | + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
4810 | + usb_make_path(catc->usbdev, info->bus_info, sizeof(info->bus_info)); | |
4811 | +} | |
4812 | + | |
4813 | +static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
4814 | +{ | |
4815 | + struct catc *catc = netdev_priv(dev); | |
4816 | + if (!catc->is_f5u011) | |
4817 | + return -EOPNOTSUPP; | |
4818 | + | |
4819 | + cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; | |
4820 | + cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; | |
4821 | + ethtool_cmd_speed_set(cmd, SPEED_10); | |
4822 | + cmd->duplex = DUPLEX_HALF; | |
4823 | + cmd->port = PORT_TP; | |
4824 | + cmd->phy_address = 0; | |
4825 | + cmd->transceiver = XCVR_INTERNAL; | |
4826 | + cmd->autoneg = AUTONEG_DISABLE; | |
4827 | + cmd->maxtxpkt = 1; | |
4828 | + cmd->maxrxpkt = 1; | |
4829 | + return 0; | |
4830 | +} | |
4831 | + | |
4832 | +static const struct ethtool_ops ops = { | |
4833 | + .get_drvinfo = catc_get_drvinfo, | |
4834 | + .get_settings = catc_get_settings, | |
4835 | + .get_link = ethtool_op_get_link | |
4836 | +}; | |
4837 | + | |
4838 | +/* | |
4839 | + * Open, close. | |
4840 | + */ | |
4841 | + | |
4842 | +static int catc_open(struct net_device *netdev) | |
4843 | +{ | |
4844 | + struct catc *catc = netdev_priv(netdev); | |
4845 | + int status; | |
4846 | + | |
4847 | + catc->irq_urb->dev = catc->usbdev; | |
4848 | + if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) { | |
4849 | + dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n", | |
4850 | + status); | |
4851 | + return -1; | |
4852 | + } | |
4853 | + | |
4854 | + netif_start_queue(netdev); | |
4855 | + | |
4856 | + if (!catc->is_f5u011) | |
4857 | + mod_timer(&catc->timer, jiffies + STATS_UPDATE); | |
4858 | + | |
4859 | + return 0; | |
4860 | +} | |
4861 | + | |
4862 | +static int catc_stop(struct net_device *netdev) | |
4863 | +{ | |
4864 | + struct catc *catc = netdev_priv(netdev); | |
4865 | + | |
4866 | + netif_stop_queue(netdev); | |
4867 | + | |
4868 | + if (!catc->is_f5u011) | |
4869 | + del_timer_sync(&catc->timer); | |
4870 | + | |
4871 | + usb_kill_urb(catc->rx_urb); | |
4872 | + usb_kill_urb(catc->tx_urb); | |
4873 | + usb_kill_urb(catc->irq_urb); | |
4874 | + usb_kill_urb(catc->ctrl_urb); | |
4875 | + | |
4876 | + return 0; | |
4877 | +} | |
4878 | + | |
4879 | +static const struct net_device_ops catc_netdev_ops = { | |
4880 | + .ndo_open = catc_open, | |
4881 | + .ndo_stop = catc_stop, | |
4882 | + .ndo_start_xmit = catc_start_xmit, | |
4883 | + | |
4884 | + .ndo_tx_timeout = catc_tx_timeout, | |
4885 | + .ndo_set_rx_mode = catc_set_multicast_list, | |
4886 | + .ndo_change_mtu = eth_change_mtu, | |
4887 | + .ndo_set_mac_address = eth_mac_addr, | |
4888 | + .ndo_validate_addr = eth_validate_addr, | |
4889 | +}; | |
4890 | + | |
4891 | +/* | |
4892 | + * USB probe, disconnect. | |
4893 | + */ | |
4894 | + | |
4895 | +static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
4896 | +{ | |
4897 | + struct device *dev = &intf->dev; | |
4898 | + struct usb_device *usbdev = interface_to_usbdev(intf); | |
4899 | + struct net_device *netdev; | |
4900 | + struct catc *catc; | |
4901 | + u8 broadcast[ETH_ALEN]; | |
4902 | + int i, pktsz; | |
4903 | + | |
4904 | + if (usb_set_interface(usbdev, | |
4905 | + intf->altsetting->desc.bInterfaceNumber, 1)) { | |
4906 | + dev_err(dev, "Can't set altsetting 1.\n"); | |
4907 | + return -EIO; | |
4908 | + } | |
4909 | + | |
4910 | + netdev = alloc_etherdev(sizeof(struct catc)); | |
4911 | + if (!netdev) | |
4912 | + return -ENOMEM; | |
4913 | + | |
4914 | + catc = netdev_priv(netdev); | |
4915 | + | |
4916 | + netdev->netdev_ops = &catc_netdev_ops; | |
4917 | + netdev->watchdog_timeo = TX_TIMEOUT; | |
4918 | + netdev->ethtool_ops = &ops; | |
4919 | + | |
4920 | + catc->usbdev = usbdev; | |
4921 | + catc->netdev = netdev; | |
4922 | + | |
4923 | + spin_lock_init(&catc->tx_lock); | |
4924 | + spin_lock_init(&catc->ctrl_lock); | |
4925 | + | |
4926 | + init_timer(&catc->timer); | |
4927 | + catc->timer.data = (long) catc; | |
4928 | + catc->timer.function = catc_stats_timer; | |
4929 | + | |
4930 | + catc->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); | |
4931 | + catc->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
4932 | + catc->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
4933 | + catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | |
4934 | + if ((!catc->ctrl_urb) || (!catc->tx_urb) || | |
4935 | + (!catc->rx_urb) || (!catc->irq_urb)) { | |
4936 | + dev_err(&intf->dev, "No free urbs available.\n"); | |
4937 | + usb_free_urb(catc->ctrl_urb); | |
4938 | + usb_free_urb(catc->tx_urb); | |
4939 | + usb_free_urb(catc->rx_urb); | |
4940 | + usb_free_urb(catc->irq_urb); | |
4941 | + free_netdev(netdev); | |
4942 | + return -ENOMEM; | |
4943 | + } | |
4944 | + | |
4945 | + /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ | |
4946 | + if (le16_to_cpu(usbdev->descriptor.idVendor) == 0x0423 && | |
4947 | + le16_to_cpu(usbdev->descriptor.idProduct) == 0xa && | |
4948 | + le16_to_cpu(catc->usbdev->descriptor.bcdDevice) == 0x0130) { | |
4949 | + dev_dbg(dev, "Testing for f5u011\n"); | |
4950 | + catc->is_f5u011 = 1; | |
4951 | + atomic_set(&catc->recq_sz, 0); | |
4952 | + pktsz = RX_PKT_SZ; | |
4953 | + } else { | |
4954 | + pktsz = RX_MAX_BURST * (PKT_SZ + 2); | |
4955 | + } | |
4956 | + | |
4957 | + usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), | |
4958 | + NULL, NULL, 0, catc_ctrl_done, catc); | |
4959 | + | |
4960 | + usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1), | |
4961 | + NULL, 0, catc_tx_done, catc); | |
4962 | + | |
4963 | + usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), | |
4964 | + catc->rx_buf, pktsz, catc_rx_done, catc); | |
4965 | + | |
4966 | + usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), | |
4967 | + catc->irq_buf, 2, catc_irq_done, catc, 1); | |
4968 | + | |
4969 | + if (!catc->is_f5u011) { | |
4970 | + dev_dbg(dev, "Checking memory size\n"); | |
4971 | + | |
4972 | + i = 0x12345678; | |
4973 | + catc_write_mem(catc, 0x7a80, &i, 4); | |
4974 | + i = 0x87654321; | |
4975 | + catc_write_mem(catc, 0xfa80, &i, 4); | |
4976 | + catc_read_mem(catc, 0x7a80, &i, 4); | |
4977 | + | |
4978 | + switch (i) { | |
4979 | + case 0x12345678: | |
4980 | + catc_set_reg(catc, TxBufCount, 8); | |
4981 | + catc_set_reg(catc, RxBufCount, 32); | |
4982 | + dev_dbg(dev, "64k Memory\n"); | |
4983 | + break; | |
4984 | + default: | |
4985 | + dev_warn(&intf->dev, | |
4986 | + "Couldn't detect memory size, assuming 32k\n"); | |
4987 | + case 0x87654321: | |
4988 | + catc_set_reg(catc, TxBufCount, 4); | |
4989 | + catc_set_reg(catc, RxBufCount, 16); | |
4990 | + dev_dbg(dev, "32k Memory\n"); | |
4991 | + break; | |
4992 | + } | |
4993 | + | |
4994 | + dev_dbg(dev, "Getting MAC from SEEROM.\n"); | |
4995 | + | |
4996 | + catc_get_mac(catc, netdev->dev_addr); | |
4997 | + | |
4998 | + dev_dbg(dev, "Setting MAC into registers.\n"); | |
4999 | + | |
5000 | + for (i = 0; i < 6; i++) | |
5001 | + catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); | |
5002 | + | |
5003 | + dev_dbg(dev, "Filling the multicast list.\n"); | |
5004 | + | |
5005 | + memset(broadcast, 0xff, ETH_ALEN); | |
5006 | + catc_multicast(broadcast, catc->multicast); | |
5007 | + catc_multicast(netdev->dev_addr, catc->multicast); | |
5008 | + catc_write_mem(catc, 0xfa80, catc->multicast, 64); | |
5009 | + | |
5010 | + dev_dbg(dev, "Clearing error counters.\n"); | |
5011 | + | |
5012 | + for (i = 0; i < 8; i++) | |
5013 | + catc_set_reg(catc, EthStats + i, 0); | |
5014 | + catc->last_stats = jiffies; | |
5015 | + | |
5016 | + dev_dbg(dev, "Enabling.\n"); | |
5017 | + | |
5018 | + catc_set_reg(catc, MaxBurst, RX_MAX_BURST); | |
5019 | + catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); | |
5020 | + catc_set_reg(catc, LEDCtrl, LEDLink); | |
5021 | + catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); | |
5022 | + } else { | |
5023 | + dev_dbg(dev, "Performing reset\n"); | |
5024 | + catc_reset(catc); | |
5025 | + catc_get_mac(catc, netdev->dev_addr); | |
5026 | + | |
5027 | + dev_dbg(dev, "Setting RX Mode\n"); | |
5028 | + catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; | |
5029 | + catc->rxmode[1] = 0; | |
5030 | + f5u011_rxmode(catc, catc->rxmode); | |
5031 | + } | |
5032 | + dev_dbg(dev, "Init done.\n"); | |
5033 | + printk(KERN_INFO "%s: %s USB Ethernet at usb-%s-%s, %pM.\n", | |
5034 | + netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", | |
5035 | + usbdev->bus->bus_name, usbdev->devpath, netdev->dev_addr); | |
5036 | + usb_set_intfdata(intf, catc); | |
5037 | + | |
5038 | + SET_NETDEV_DEV(netdev, &intf->dev); | |
5039 | + if (register_netdev(netdev) != 0) { | |
5040 | + usb_set_intfdata(intf, NULL); | |
5041 | + usb_free_urb(catc->ctrl_urb); | |
5042 | + usb_free_urb(catc->tx_urb); | |
5043 | + usb_free_urb(catc->rx_urb); | |
5044 | + usb_free_urb(catc->irq_urb); | |
5045 | + free_netdev(netdev); | |
5046 | + return -EIO; | |
5047 | + } | |
5048 | + return 0; | |
5049 | +} | |
5050 | + | |
5051 | +static void catc_disconnect(struct usb_interface *intf) | |
5052 | +{ | |
5053 | + struct catc *catc = usb_get_intfdata(intf); | |
5054 | + | |
5055 | + usb_set_intfdata(intf, NULL); | |
5056 | + if (catc) { | |
5057 | + unregister_netdev(catc->netdev); | |
5058 | + usb_free_urb(catc->ctrl_urb); | |
5059 | + usb_free_urb(catc->tx_urb); | |
5060 | + usb_free_urb(catc->rx_urb); | |
5061 | + usb_free_urb(catc->irq_urb); | |
5062 | + free_netdev(catc->netdev); | |
5063 | + } | |
5064 | +} | |
5065 | + | |
5066 | +/* | |
5067 | + * Module functions and tables. | |
5068 | + */ | |
5069 | + | |
5070 | +static struct usb_device_id catc_id_table [] = { | |
5071 | + { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ | |
5072 | + { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ | |
5073 | + { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ | |
5074 | + { } | |
5075 | +}; | |
5076 | + | |
5077 | +MODULE_DEVICE_TABLE(usb, catc_id_table); | |
5078 | + | |
5079 | +static struct usb_driver catc_driver = { | |
5080 | + .name = driver_name, | |
5081 | + .probe = catc_probe, | |
5082 | + .disconnect = catc_disconnect, | |
5083 | + .id_table = catc_id_table, | |
5084 | + .disable_hub_initiated_lpm = 1, | |
5085 | +}; | |
5086 | + | |
5087 | +module_usb_driver(catc_driver); | |
5088 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/cdc_eem.c backports-3.18.1-1/drivers/net/usb/cdc_eem.c | |
5089 | --- backports-3.18.1-1.org/drivers/net/usb/cdc_eem.c 1970-01-01 01:00:00.000000000 +0100 | |
5090 | +++ backports-3.18.1-1/drivers/net/usb/cdc_eem.c 2014-12-16 18:39:45.000000000 +0100 | |
5091 | @@ -0,0 +1,381 @@ | |
5092 | +/* | |
5093 | + * USB CDC EEM network interface driver | |
5094 | + * Copyright (C) 2009 Oberthur Technologies | |
5095 | + * by Omar Laazimani, Olivier Condemine | |
5096 | + * | |
5097 | + * This program is free software; you can redistribute it and/or modify | |
5098 | + * it under the terms of the GNU General Public License as published by | |
5099 | + * the Free Software Foundation; either version 2 of the License, or | |
5100 | + * (at your option) any later version. | |
5101 | + * | |
5102 | + * This program is distributed in the hope that it will be useful, | |
5103 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
5104 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
5105 | + * GNU General Public License for more details. | |
5106 | + * | |
5107 | + * You should have received a copy of the GNU General Public License | |
5108 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
5109 | + */ | |
5110 | + | |
5111 | +#include <linux/module.h> | |
5112 | +#include <linux/netdevice.h> | |
5113 | +#include <linux/etherdevice.h> | |
5114 | +#include <linux/ctype.h> | |
5115 | +#include <linux/ethtool.h> | |
5116 | +#include <linux/workqueue.h> | |
5117 | +#include <linux/mii.h> | |
5118 | +#include <linux/usb.h> | |
5119 | +#include <linux/crc32.h> | |
5120 | +#include <linux/usb/cdc.h> | |
5121 | +#include <linux/usb/usbnet.h> | |
5122 | +#include <linux/gfp.h> | |
5123 | +#include <linux/if_vlan.h> | |
5124 | + | |
5125 | + | |
5126 | +/* | |
5127 | + * This driver is an implementation of the CDC "Ethernet Emulation | |
5128 | + * Model" (EEM) specification, which encapsulates Ethernet frames | |
5129 | + * for transport over USB using a simpler USB device model than the | |
5130 | + * previous CDC "Ethernet Control Model" (ECM, or "CDC Ethernet"). | |
5131 | + * | |
5132 | + * For details, see www.usb.org/developers/devclass_docs/CDC_EEM10.pdf | |
5133 | + * | |
5134 | + * This version has been tested with GIGAntIC WuaoW SIM Smart Card on 2.6.24, | |
5135 | + * 2.6.27 and 2.6.30rc2 kernel. | |
5136 | + * It has also been validated on Openmoko Om 2008.12 (based on 2.6.24 kernel). | |
5137 | + * build on 23-April-2009 | |
5138 | + */ | |
5139 | + | |
5140 | +#define EEM_HEAD 2 /* 2 byte header */ | |
5141 | + | |
5142 | +/*-------------------------------------------------------------------------*/ | |
5143 | + | |
5144 | +static void eem_linkcmd_complete(struct urb *urb) | |
5145 | +{ | |
5146 | + dev_kfree_skb(urb->context); | |
5147 | + usb_free_urb(urb); | |
5148 | +} | |
5149 | + | |
5150 | +static void eem_linkcmd(struct usbnet *dev, struct sk_buff *skb) | |
5151 | +{ | |
5152 | + struct urb *urb; | |
5153 | + int status; | |
5154 | + | |
5155 | + urb = usb_alloc_urb(0, GFP_ATOMIC); | |
5156 | + if (!urb) | |
5157 | + goto fail; | |
5158 | + | |
5159 | + usb_fill_bulk_urb(urb, dev->udev, dev->out, | |
5160 | + skb->data, skb->len, eem_linkcmd_complete, skb); | |
5161 | + | |
5162 | + status = usb_submit_urb(urb, GFP_ATOMIC); | |
5163 | + if (status) { | |
5164 | + usb_free_urb(urb); | |
5165 | +fail: | |
5166 | + dev_kfree_skb(skb); | |
5167 | + netdev_warn(dev->net, "link cmd failure\n"); | |
5168 | + return; | |
5169 | + } | |
5170 | +} | |
5171 | + | |
5172 | +static int eem_bind(struct usbnet *dev, struct usb_interface *intf) | |
5173 | +{ | |
5174 | + int status = 0; | |
5175 | + | |
5176 | + status = usbnet_get_endpoints(dev, intf); | |
5177 | + if (status < 0) { | |
5178 | + usb_set_intfdata(intf, NULL); | |
5179 | + usb_driver_release_interface(driver_of(intf), intf); | |
5180 | + return status; | |
5181 | + } | |
5182 | + | |
5183 | + /* no jumbogram (16K) support for now */ | |
5184 | + | |
5185 | + dev->net->hard_header_len += EEM_HEAD + ETH_FCS_LEN + VLAN_HLEN; | |
5186 | + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | |
5187 | + | |
5188 | + return 0; | |
5189 | +} | |
5190 | + | |
5191 | +/* | |
5192 | + * EEM permits packing multiple Ethernet frames into USB transfers | |
5193 | + * (a "bundle"), but for TX we don't try to do that. | |
5194 | + */ | |
5195 | +static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
5196 | + gfp_t flags) | |
5197 | +{ | |
5198 | + struct sk_buff *skb2 = NULL; | |
5199 | + u16 len = skb->len; | |
5200 | + u32 crc = 0; | |
5201 | + int padlen = 0; | |
5202 | + | |
5203 | + /* When ((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket) is | |
5204 | + * zero, stick two bytes of zero length EEM packet on the end. | |
5205 | + * Else the framework would add invalid single byte padding, | |
5206 | + * since it can't know whether ZLPs will be handled right by | |
5207 | + * all the relevant hardware and software. | |
5208 | + */ | |
5209 | + if (!((len + EEM_HEAD + ETH_FCS_LEN) % dev->maxpacket)) | |
5210 | + padlen += 2; | |
5211 | + | |
5212 | + if (!skb_cloned(skb)) { | |
5213 | + int headroom = skb_headroom(skb); | |
5214 | + int tailroom = skb_tailroom(skb); | |
5215 | + | |
5216 | + if ((tailroom >= ETH_FCS_LEN + padlen) && | |
5217 | + (headroom >= EEM_HEAD)) | |
5218 | + goto done; | |
5219 | + | |
5220 | + if ((headroom + tailroom) | |
5221 | + > (EEM_HEAD + ETH_FCS_LEN + padlen)) { | |
5222 | + skb->data = memmove(skb->head + | |
5223 | + EEM_HEAD, | |
5224 | + skb->data, | |
5225 | + skb->len); | |
5226 | + skb_set_tail_pointer(skb, len); | |
5227 | + goto done; | |
5228 | + } | |
5229 | + } | |
5230 | + | |
5231 | + skb2 = skb_copy_expand(skb, EEM_HEAD, ETH_FCS_LEN + padlen, flags); | |
5232 | + if (!skb2) | |
5233 | + return NULL; | |
5234 | + | |
5235 | + dev_kfree_skb_any(skb); | |
5236 | + skb = skb2; | |
5237 | + | |
5238 | +done: | |
5239 | + /* we don't use the "no Ethernet CRC" option */ | |
5240 | + crc = crc32_le(~0, skb->data, skb->len); | |
5241 | + crc = ~crc; | |
5242 | + | |
5243 | + put_unaligned_le32(crc, skb_put(skb, 4)); | |
5244 | + | |
5245 | + /* EEM packet header format: | |
5246 | + * b0..13: length of ethernet frame | |
5247 | + * b14: bmCRC (1 == valid Ethernet CRC) | |
5248 | + * b15: bmType (0 == data) | |
5249 | + */ | |
5250 | + len = skb->len; | |
5251 | + put_unaligned_le16(BIT(14) | len, skb_push(skb, 2)); | |
5252 | + | |
5253 | + /* Bundle a zero length EEM packet if needed */ | |
5254 | + if (padlen) | |
5255 | + put_unaligned_le16(0, skb_put(skb, 2)); | |
5256 | + | |
5257 | + return skb; | |
5258 | +} | |
5259 | + | |
5260 | +static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
5261 | +{ | |
5262 | + /* | |
5263 | + * Our task here is to strip off framing, leaving skb with one | |
5264 | + * data frame for the usbnet framework code to process. But we | |
5265 | + * may have received multiple EEM payloads, or command payloads. | |
5266 | + * So we must process _everything_ as if it's a header, except | |
5267 | + * maybe the last data payload | |
5268 | + * | |
5269 | + * REVISIT the framework needs updating so that when we consume | |
5270 | + * all payloads (the last or only message was a command, or a | |
5271 | + * zero length EEM packet) that is not accounted as an rx_error. | |
5272 | + */ | |
5273 | + do { | |
5274 | + struct sk_buff *skb2 = NULL; | |
5275 | + u16 header; | |
5276 | + u16 len = 0; | |
5277 | + | |
5278 | + /* incomplete EEM header? */ | |
5279 | + if (skb->len < EEM_HEAD) | |
5280 | + return 0; | |
5281 | + | |
5282 | + /* | |
5283 | + * EEM packet header format: | |
5284 | + * b0..14: EEM type dependent (Data or Command) | |
5285 | + * b15: bmType | |
5286 | + */ | |
5287 | + header = get_unaligned_le16(skb->data); | |
5288 | + skb_pull(skb, EEM_HEAD); | |
5289 | + | |
5290 | + /* | |
5291 | + * The bmType bit helps to denote when EEM | |
5292 | + * packet is data or command : | |
5293 | + * bmType = 0 : EEM data payload | |
5294 | + * bmType = 1 : EEM (link) command | |
5295 | + */ | |
5296 | + if (header & BIT(15)) { | |
5297 | + u16 bmEEMCmd; | |
5298 | + | |
5299 | + /* | |
5300 | + * EEM (link) command packet: | |
5301 | + * b0..10: bmEEMCmdParam | |
5302 | + * b11..13: bmEEMCmd | |
5303 | + * b14: bmReserved (must be 0) | |
5304 | + * b15: 1 (EEM command) | |
5305 | + */ | |
5306 | + if (header & BIT(14)) { | |
5307 | + netdev_dbg(dev->net, "reserved command %04x\n", | |
5308 | + header); | |
5309 | + continue; | |
5310 | + } | |
5311 | + | |
5312 | + bmEEMCmd = (header >> 11) & 0x7; | |
5313 | + switch (bmEEMCmd) { | |
5314 | + | |
5315 | + /* Responding to echo requests is mandatory. */ | |
5316 | + case 0: /* Echo command */ | |
5317 | + len = header & 0x7FF; | |
5318 | + | |
5319 | + /* bogus command? */ | |
5320 | + if (skb->len < len) | |
5321 | + return 0; | |
5322 | + | |
5323 | + skb2 = skb_clone(skb, GFP_ATOMIC); | |
5324 | + if (unlikely(!skb2)) | |
5325 | + goto next; | |
5326 | + skb_trim(skb2, len); | |
5327 | + put_unaligned_le16(BIT(15) | (1 << 11) | len, | |
5328 | + skb_push(skb2, 2)); | |
5329 | + eem_linkcmd(dev, skb2); | |
5330 | + break; | |
5331 | + | |
5332 | + /* | |
5333 | + * Host may choose to ignore hints. | |
5334 | + * - suspend: peripheral ready to suspend | |
5335 | + * - response: suggest N millisec polling | |
5336 | + * - response complete: suggest N sec polling | |
5337 | + * | |
5338 | + * Suspend is reported and maybe heeded. | |
5339 | + */ | |
5340 | + case 2: /* Suspend hint */ | |
5341 | + usbnet_device_suggests_idle(dev); | |
5342 | + continue; | |
5343 | + case 3: /* Response hint */ | |
5344 | + case 4: /* Response complete hint */ | |
5345 | + continue; | |
5346 | + | |
5347 | + /* | |
5348 | + * Hosts should never receive host-to-peripheral | |
5349 | + * or reserved command codes; or responses to an | |
5350 | + * echo command we didn't send. | |
5351 | + */ | |
5352 | + case 1: /* Echo response */ | |
5353 | + case 5: /* Tickle */ | |
5354 | + default: /* reserved */ | |
5355 | + netdev_warn(dev->net, | |
5356 | + "unexpected link command %d\n", | |
5357 | + bmEEMCmd); | |
5358 | + continue; | |
5359 | + } | |
5360 | + | |
5361 | + } else { | |
5362 | + u32 crc, crc2; | |
5363 | + int is_last; | |
5364 | + | |
5365 | + /* zero length EEM packet? */ | |
5366 | + if (header == 0) | |
5367 | + continue; | |
5368 | + | |
5369 | + /* | |
5370 | + * EEM data packet header : | |
5371 | + * b0..13: length of ethernet frame | |
5372 | + * b14: bmCRC | |
5373 | + * b15: 0 (EEM data) | |
5374 | + */ | |
5375 | + len = header & 0x3FFF; | |
5376 | + | |
5377 | + /* bogus EEM payload? */ | |
5378 | + if (skb->len < len) | |
5379 | + return 0; | |
5380 | + | |
5381 | + /* bogus ethernet frame? */ | |
5382 | + if (len < (ETH_HLEN + ETH_FCS_LEN)) | |
5383 | + goto next; | |
5384 | + | |
5385 | + /* | |
5386 | + * Treat the last payload differently: framework | |
5387 | + * code expects our "fixup" to have stripped off | |
5388 | + * headers, so "skb" is a data packet (or error). | |
5389 | + * Else if it's not the last payload, keep "skb" | |
5390 | + * for further processing. | |
5391 | + */ | |
5392 | + is_last = (len == skb->len); | |
5393 | + if (is_last) | |
5394 | + skb2 = skb; | |
5395 | + else { | |
5396 | + skb2 = skb_clone(skb, GFP_ATOMIC); | |
5397 | + if (unlikely(!skb2)) | |
5398 | + return 0; | |
5399 | + } | |
5400 | + | |
5401 | + /* | |
5402 | + * The bmCRC helps to denote when the CRC field in | |
5403 | + * the Ethernet frame contains a calculated CRC: | |
5404 | + * bmCRC = 1 : CRC is calculated | |
5405 | + * bmCRC = 0 : CRC = 0xDEADBEEF | |
5406 | + */ | |
5407 | + if (header & BIT(14)) { | |
5408 | + crc = get_unaligned_le32(skb2->data | |
5409 | + + len - ETH_FCS_LEN); | |
5410 | + crc2 = ~crc32_le(~0, skb2->data, skb2->len | |
5411 | + - ETH_FCS_LEN); | |
5412 | + } else { | |
5413 | + crc = get_unaligned_be32(skb2->data | |
5414 | + + len - ETH_FCS_LEN); | |
5415 | + crc2 = 0xdeadbeef; | |
5416 | + } | |
5417 | + skb_trim(skb2, len - ETH_FCS_LEN); | |
5418 | + | |
5419 | + if (is_last) | |
5420 | + return crc == crc2; | |
5421 | + | |
5422 | + if (unlikely(crc != crc2)) { | |
5423 | + dev->net->stats.rx_errors++; | |
5424 | + dev_kfree_skb_any(skb2); | |
5425 | + } else | |
5426 | + usbnet_skb_return(dev, skb2); | |
5427 | + } | |
5428 | + | |
5429 | +next: | |
5430 | + skb_pull(skb, len); | |
5431 | + } while (skb->len); | |
5432 | + | |
5433 | + return 1; | |
5434 | +} | |
5435 | + | |
5436 | +static const struct driver_info eem_info = { | |
5437 | + .description = "CDC EEM Device", | |
5438 | + .flags = FLAG_ETHER | FLAG_POINTTOPOINT, | |
5439 | + .bind = eem_bind, | |
5440 | + .rx_fixup = eem_rx_fixup, | |
5441 | + .tx_fixup = eem_tx_fixup, | |
5442 | +}; | |
5443 | + | |
5444 | +/*-------------------------------------------------------------------------*/ | |
5445 | + | |
5446 | +static const struct usb_device_id products[] = { | |
5447 | +{ | |
5448 | + USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_EEM, | |
5449 | + USB_CDC_PROTO_EEM), | |
5450 | + .driver_info = (unsigned long) &eem_info, | |
5451 | +}, | |
5452 | +{ | |
5453 | + /* EMPTY == end of list */ | |
5454 | +}, | |
5455 | +}; | |
5456 | +MODULE_DEVICE_TABLE(usb, products); | |
5457 | + | |
5458 | +static struct usb_driver eem_driver = { | |
5459 | + .name = "cdc_eem", | |
5460 | + .id_table = products, | |
5461 | + .probe = usbnet_probe, | |
5462 | + .disconnect = usbnet_disconnect, | |
5463 | + .suspend = usbnet_suspend, | |
5464 | + .resume = usbnet_resume, | |
5465 | + .disable_hub_initiated_lpm = 1, | |
5466 | +}; | |
5467 | + | |
5468 | +module_usb_driver(eem_driver); | |
5469 | + | |
5470 | +MODULE_AUTHOR("Omar Laazimani <omar.oberthur@gmail.com>"); | |
5471 | +MODULE_DESCRIPTION("USB CDC EEM"); | |
5472 | +MODULE_LICENSE("GPL"); | |
5473 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/cdc-phonet.c backports-3.18.1-1/drivers/net/usb/cdc-phonet.c | |
5474 | --- backports-3.18.1-1.org/drivers/net/usb/cdc-phonet.c 1970-01-01 01:00:00.000000000 +0100 | |
5475 | +++ backports-3.18.1-1/drivers/net/usb/cdc-phonet.c 2014-12-16 18:39:45.000000000 +0100 | |
5476 | @@ -0,0 +1,466 @@ | |
5477 | +/* | |
5478 | + * phonet.c -- USB CDC Phonet host driver | |
5479 | + * | |
5480 | + * Copyright (C) 2008-2009 Nokia Corporation. All rights reserved. | |
5481 | + * | |
5482 | + * Author: Rémi Denis-Courmont | |
5483 | + * | |
5484 | + * This program is free software; you can redistribute it and/or | |
5485 | + * modify it under the terms of the GNU General Public License | |
5486 | + * version 2 as published by the Free Software Foundation. | |
5487 | + * | |
5488 | + * This program is distributed in the hope that it will be useful, but | |
5489 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | |
5490 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Â See the GNU | |
5491 | + * General Public License for more details. | |
5492 | + * | |
5493 | + * You should have received a copy of the GNU General Public License | |
5494 | + * along with this program; if not, write to the Free Software | |
5495 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
5496 | + * 02110-1301 USA | |
5497 | + */ | |
5498 | + | |
5499 | +#include <linux/kernel.h> | |
5500 | +#include <linux/mm.h> | |
5501 | +#include <linux/module.h> | |
5502 | +#include <linux/gfp.h> | |
5503 | +#include <linux/usb.h> | |
5504 | +#include <linux/usb/cdc.h> | |
5505 | +#include <linux/netdevice.h> | |
5506 | +#include <linux/if_arp.h> | |
5507 | +#include <linux/if_phonet.h> | |
5508 | +#include <linux/phonet.h> | |
5509 | + | |
5510 | +#define PN_MEDIA_USB 0x1B | |
5511 | + | |
5512 | +static const unsigned rxq_size = 17; | |
5513 | + | |
5514 | +struct usbpn_dev { | |
5515 | + struct net_device *dev; | |
5516 | + | |
5517 | + struct usb_interface *intf, *data_intf; | |
5518 | + struct usb_device *usb; | |
5519 | + unsigned int tx_pipe, rx_pipe; | |
5520 | + u8 active_setting; | |
5521 | + u8 disconnected; | |
5522 | + | |
5523 | + unsigned tx_queue; | |
5524 | + spinlock_t tx_lock; | |
5525 | + | |
5526 | + spinlock_t rx_lock; | |
5527 | + struct sk_buff *rx_skb; | |
5528 | + struct urb *urbs[0]; | |
5529 | +}; | |
5530 | + | |
5531 | +static void tx_complete(struct urb *req); | |
5532 | +static void rx_complete(struct urb *req); | |
5533 | + | |
5534 | +/* | |
5535 | + * Network device callbacks | |
5536 | + */ | |
5537 | +static netdev_tx_t usbpn_xmit(struct sk_buff *skb, struct net_device *dev) | |
5538 | +{ | |
5539 | + struct usbpn_dev *pnd = netdev_priv(dev); | |
5540 | + struct urb *req = NULL; | |
5541 | + unsigned long flags; | |
5542 | + int err; | |
5543 | + | |
5544 | + if (skb->protocol != htons(ETH_P_PHONET)) | |
5545 | + goto drop; | |
5546 | + | |
5547 | + req = usb_alloc_urb(0, GFP_ATOMIC); | |
5548 | + if (!req) | |
5549 | + goto drop; | |
5550 | + usb_fill_bulk_urb(req, pnd->usb, pnd->tx_pipe, skb->data, skb->len, | |
5551 | + tx_complete, skb); | |
5552 | + req->transfer_flags = URB_ZERO_PACKET; | |
5553 | + err = usb_submit_urb(req, GFP_ATOMIC); | |
5554 | + if (err) { | |
5555 | + usb_free_urb(req); | |
5556 | + goto drop; | |
5557 | + } | |
5558 | + | |
5559 | + spin_lock_irqsave(&pnd->tx_lock, flags); | |
5560 | + pnd->tx_queue++; | |
5561 | + if (pnd->tx_queue >= dev->tx_queue_len) | |
5562 | + netif_stop_queue(dev); | |
5563 | + spin_unlock_irqrestore(&pnd->tx_lock, flags); | |
5564 | + return NETDEV_TX_OK; | |
5565 | + | |
5566 | +drop: | |
5567 | + dev_kfree_skb(skb); | |
5568 | + dev->stats.tx_dropped++; | |
5569 | + return NETDEV_TX_OK; | |
5570 | +} | |
5571 | + | |
5572 | +static void tx_complete(struct urb *req) | |
5573 | +{ | |
5574 | + struct sk_buff *skb = req->context; | |
5575 | + struct net_device *dev = skb->dev; | |
5576 | + struct usbpn_dev *pnd = netdev_priv(dev); | |
5577 | + int status = req->status; | |
5578 | + | |
5579 | + switch (status) { | |
5580 | + case 0: | |
5581 | + dev->stats.tx_bytes += skb->len; | |
5582 | + break; | |
5583 | + | |
5584 | + case -ENOENT: | |
5585 | + case -ECONNRESET: | |
5586 | + case -ESHUTDOWN: | |
5587 | + dev->stats.tx_aborted_errors++; | |
5588 | + default: | |
5589 | + dev->stats.tx_errors++; | |
5590 | + dev_dbg(&dev->dev, "TX error (%d)\n", status); | |
5591 | + } | |
5592 | + dev->stats.tx_packets++; | |
5593 | + | |
5594 | + spin_lock(&pnd->tx_lock); | |
5595 | + pnd->tx_queue--; | |
5596 | + netif_wake_queue(dev); | |
5597 | + spin_unlock(&pnd->tx_lock); | |
5598 | + | |
5599 | + dev_kfree_skb_any(skb); | |
5600 | + usb_free_urb(req); | |
5601 | +} | |
5602 | + | |
5603 | +static int rx_submit(struct usbpn_dev *pnd, struct urb *req, gfp_t gfp_flags) | |
5604 | +{ | |
5605 | + struct net_device *dev = pnd->dev; | |
5606 | + struct page *page; | |
5607 | + int err; | |
5608 | + | |
5609 | + page = __skb_alloc_page(gfp_flags | __GFP_NOMEMALLOC, NULL); | |
5610 | + if (!page) | |
5611 | + return -ENOMEM; | |
5612 | + | |
5613 | + usb_fill_bulk_urb(req, pnd->usb, pnd->rx_pipe, page_address(page), | |
5614 | + PAGE_SIZE, rx_complete, dev); | |
5615 | + req->transfer_flags = 0; | |
5616 | + err = usb_submit_urb(req, gfp_flags); | |
5617 | + if (unlikely(err)) { | |
5618 | + dev_dbg(&dev->dev, "RX submit error (%d)\n", err); | |
5619 | + put_page(page); | |
5620 | + } | |
5621 | + return err; | |
5622 | +} | |
5623 | + | |
5624 | +static void rx_complete(struct urb *req) | |
5625 | +{ | |
5626 | + struct net_device *dev = req->context; | |
5627 | + struct usbpn_dev *pnd = netdev_priv(dev); | |
5628 | + struct page *page = virt_to_page(req->transfer_buffer); | |
5629 | + struct sk_buff *skb; | |
5630 | + unsigned long flags; | |
5631 | + int status = req->status; | |
5632 | + | |
5633 | + switch (status) { | |
5634 | + case 0: | |
5635 | + spin_lock_irqsave(&pnd->rx_lock, flags); | |
5636 | + skb = pnd->rx_skb; | |
5637 | + if (!skb) { | |
5638 | + skb = pnd->rx_skb = netdev_alloc_skb(dev, 12); | |
5639 | + if (likely(skb)) { | |
5640 | + /* Can't use pskb_pull() on page in IRQ */ | |
5641 | + memcpy(skb_put(skb, 1), page_address(page), 1); | |
5642 | + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, | |
5643 | + page, 1, req->actual_length, | |
5644 | + PAGE_SIZE); | |
5645 | + page = NULL; | |
5646 | + } | |
5647 | + } else { | |
5648 | + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, | |
5649 | + page, 0, req->actual_length, | |
5650 | + PAGE_SIZE); | |
5651 | + page = NULL; | |
5652 | + } | |
5653 | + if (req->actual_length < PAGE_SIZE) | |
5654 | + pnd->rx_skb = NULL; /* Last fragment */ | |
5655 | + else | |
5656 | + skb = NULL; | |
5657 | + spin_unlock_irqrestore(&pnd->rx_lock, flags); | |
5658 | + if (skb) { | |
5659 | + skb->protocol = htons(ETH_P_PHONET); | |
5660 | + skb_reset_mac_header(skb); | |
5661 | + __skb_pull(skb, 1); | |
5662 | + skb->dev = dev; | |
5663 | + dev->stats.rx_packets++; | |
5664 | + dev->stats.rx_bytes += skb->len; | |
5665 | + | |
5666 | + netif_rx(skb); | |
5667 | + } | |
5668 | + goto resubmit; | |
5669 | + | |
5670 | + case -ENOENT: | |
5671 | + case -ECONNRESET: | |
5672 | + case -ESHUTDOWN: | |
5673 | + req = NULL; | |
5674 | + break; | |
5675 | + | |
5676 | + case -EOVERFLOW: | |
5677 | + dev->stats.rx_over_errors++; | |
5678 | + dev_dbg(&dev->dev, "RX overflow\n"); | |
5679 | + break; | |
5680 | + | |
5681 | + case -EILSEQ: | |
5682 | + dev->stats.rx_crc_errors++; | |
5683 | + break; | |
5684 | + } | |
5685 | + | |
5686 | + dev->stats.rx_errors++; | |
5687 | +resubmit: | |
5688 | + if (page) | |
5689 | + put_page(page); | |
5690 | + if (req) | |
5691 | + rx_submit(pnd, req, GFP_ATOMIC | __GFP_COLD); | |
5692 | +} | |
5693 | + | |
5694 | +static int usbpn_close(struct net_device *dev); | |
5695 | + | |
5696 | +static int usbpn_open(struct net_device *dev) | |
5697 | +{ | |
5698 | + struct usbpn_dev *pnd = netdev_priv(dev); | |
5699 | + int err; | |
5700 | + unsigned i; | |
5701 | + unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber; | |
5702 | + | |
5703 | + err = usb_set_interface(pnd->usb, num, pnd->active_setting); | |
5704 | + if (err) | |
5705 | + return err; | |
5706 | + | |
5707 | + for (i = 0; i < rxq_size; i++) { | |
5708 | + struct urb *req = usb_alloc_urb(0, GFP_KERNEL); | |
5709 | + | |
5710 | + if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) { | |
5711 | + usb_free_urb(req); | |
5712 | + usbpn_close(dev); | |
5713 | + return -ENOMEM; | |
5714 | + } | |
5715 | + pnd->urbs[i] = req; | |
5716 | + } | |
5717 | + | |
5718 | + netif_wake_queue(dev); | |
5719 | + return 0; | |
5720 | +} | |
5721 | + | |
5722 | +static int usbpn_close(struct net_device *dev) | |
5723 | +{ | |
5724 | + struct usbpn_dev *pnd = netdev_priv(dev); | |
5725 | + unsigned i; | |
5726 | + unsigned num = pnd->data_intf->cur_altsetting->desc.bInterfaceNumber; | |
5727 | + | |
5728 | + netif_stop_queue(dev); | |
5729 | + | |
5730 | + for (i = 0; i < rxq_size; i++) { | |
5731 | + struct urb *req = pnd->urbs[i]; | |
5732 | + | |
5733 | + if (!req) | |
5734 | + continue; | |
5735 | + usb_kill_urb(req); | |
5736 | + usb_free_urb(req); | |
5737 | + pnd->urbs[i] = NULL; | |
5738 | + } | |
5739 | + | |
5740 | + return usb_set_interface(pnd->usb, num, !pnd->active_setting); | |
5741 | +} | |
5742 | + | |
5743 | +static int usbpn_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |
5744 | +{ | |
5745 | + struct if_phonet_req *req = (struct if_phonet_req *)ifr; | |
5746 | + | |
5747 | + switch (cmd) { | |
5748 | + case SIOCPNGAUTOCONF: | |
5749 | + req->ifr_phonet_autoconf.device = PN_DEV_PC; | |
5750 | + return 0; | |
5751 | + } | |
5752 | + return -ENOIOCTLCMD; | |
5753 | +} | |
5754 | + | |
5755 | +static int usbpn_set_mtu(struct net_device *dev, int new_mtu) | |
5756 | +{ | |
5757 | + if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) | |
5758 | + return -EINVAL; | |
5759 | + | |
5760 | + dev->mtu = new_mtu; | |
5761 | + return 0; | |
5762 | +} | |
5763 | + | |
5764 | +static const struct net_device_ops usbpn_ops = { | |
5765 | + .ndo_open = usbpn_open, | |
5766 | + .ndo_stop = usbpn_close, | |
5767 | + .ndo_start_xmit = usbpn_xmit, | |
5768 | + .ndo_do_ioctl = usbpn_ioctl, | |
5769 | + .ndo_change_mtu = usbpn_set_mtu, | |
5770 | +}; | |
5771 | + | |
5772 | +static void usbpn_setup(struct net_device *dev) | |
5773 | +{ | |
5774 | + dev->features = 0; | |
5775 | + dev->netdev_ops = &usbpn_ops, | |
5776 | + dev->header_ops = &phonet_header_ops; | |
5777 | + dev->type = ARPHRD_PHONET; | |
5778 | + dev->flags = IFF_POINTOPOINT | IFF_NOARP; | |
5779 | + dev->mtu = PHONET_MAX_MTU; | |
5780 | + dev->hard_header_len = 1; | |
5781 | + dev->dev_addr[0] = PN_MEDIA_USB; | |
5782 | + dev->addr_len = 1; | |
5783 | + dev->tx_queue_len = 3; | |
5784 | + | |
5785 | + dev->destructor = free_netdev; | |
5786 | +} | |
5787 | + | |
5788 | +/* | |
5789 | + * USB driver callbacks | |
5790 | + */ | |
5791 | +static struct usb_device_id usbpn_ids[] = { | |
5792 | + { | |
5793 | + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | |
5794 | + | USB_DEVICE_ID_MATCH_INT_CLASS | |
5795 | + | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | |
5796 | + .idVendor = 0x0421, /* Nokia */ | |
5797 | + .bInterfaceClass = USB_CLASS_COMM, | |
5798 | + .bInterfaceSubClass = 0xFE, | |
5799 | + }, | |
5800 | + { }, | |
5801 | +}; | |
5802 | + | |
5803 | +MODULE_DEVICE_TABLE(usb, usbpn_ids); | |
5804 | + | |
5805 | +static struct usb_driver usbpn_driver; | |
5806 | + | |
5807 | +static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |
5808 | +{ | |
5809 | + static const char ifname[] = "usbpn%d"; | |
5810 | + const struct usb_cdc_union_desc *union_header = NULL; | |
5811 | + const struct usb_host_interface *data_desc; | |
5812 | + struct usb_interface *data_intf; | |
5813 | + struct usb_device *usbdev = interface_to_usbdev(intf); | |
5814 | + struct net_device *dev; | |
5815 | + struct usbpn_dev *pnd; | |
5816 | + u8 *data; | |
5817 | + int phonet = 0; | |
5818 | + int len, err; | |
5819 | + | |
5820 | + data = intf->altsetting->extra; | |
5821 | + len = intf->altsetting->extralen; | |
5822 | + while (len >= 3) { | |
5823 | + u8 dlen = data[0]; | |
5824 | + if (dlen < 3) | |
5825 | + return -EINVAL; | |
5826 | + | |
5827 | + /* bDescriptorType */ | |
5828 | + if (data[1] == USB_DT_CS_INTERFACE) { | |
5829 | + /* bDescriptorSubType */ | |
5830 | + switch (data[2]) { | |
5831 | + case USB_CDC_UNION_TYPE: | |
5832 | + if (union_header || dlen < 5) | |
5833 | + break; | |
5834 | + union_header = | |
5835 | + (struct usb_cdc_union_desc *)data; | |
5836 | + break; | |
5837 | + case 0xAB: | |
5838 | + phonet = 1; | |
5839 | + break; | |
5840 | + } | |
5841 | + } | |
5842 | + data += dlen; | |
5843 | + len -= dlen; | |
5844 | + } | |
5845 | + | |
5846 | + if (!union_header || !phonet) | |
5847 | + return -EINVAL; | |
5848 | + | |
5849 | + data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0); | |
5850 | + if (data_intf == NULL) | |
5851 | + return -ENODEV; | |
5852 | + /* Data interface has one inactive and one active setting */ | |
5853 | + if (data_intf->num_altsetting != 2) | |
5854 | + return -EINVAL; | |
5855 | + if (data_intf->altsetting[0].desc.bNumEndpoints == 0 && | |
5856 | + data_intf->altsetting[1].desc.bNumEndpoints == 2) | |
5857 | + data_desc = data_intf->altsetting + 1; | |
5858 | + else | |
5859 | + if (data_intf->altsetting[0].desc.bNumEndpoints == 2 && | |
5860 | + data_intf->altsetting[1].desc.bNumEndpoints == 0) | |
5861 | + data_desc = data_intf->altsetting; | |
5862 | + else | |
5863 | + return -EINVAL; | |
5864 | + | |
5865 | + dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size, | |
5866 | + ifname, NET_NAME_UNKNOWN, usbpn_setup); | |
5867 | + if (!dev) | |
5868 | + return -ENOMEM; | |
5869 | + | |
5870 | + pnd = netdev_priv(dev); | |
5871 | + SET_NETDEV_DEV(dev, &intf->dev); | |
5872 | + | |
5873 | + pnd->dev = dev; | |
5874 | + pnd->usb = usbdev; | |
5875 | + pnd->intf = intf; | |
5876 | + pnd->data_intf = data_intf; | |
5877 | + spin_lock_init(&pnd->tx_lock); | |
5878 | + spin_lock_init(&pnd->rx_lock); | |
5879 | + /* Endpoints */ | |
5880 | + if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) { | |
5881 | + pnd->rx_pipe = usb_rcvbulkpipe(usbdev, | |
5882 | + data_desc->endpoint[0].desc.bEndpointAddress); | |
5883 | + pnd->tx_pipe = usb_sndbulkpipe(usbdev, | |
5884 | + data_desc->endpoint[1].desc.bEndpointAddress); | |
5885 | + } else { | |
5886 | + pnd->rx_pipe = usb_rcvbulkpipe(usbdev, | |
5887 | + data_desc->endpoint[1].desc.bEndpointAddress); | |
5888 | + pnd->tx_pipe = usb_sndbulkpipe(usbdev, | |
5889 | + data_desc->endpoint[0].desc.bEndpointAddress); | |
5890 | + } | |
5891 | + pnd->active_setting = data_desc - data_intf->altsetting; | |
5892 | + | |
5893 | + err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd); | |
5894 | + if (err) | |
5895 | + goto out; | |
5896 | + | |
5897 | + /* Force inactive mode until the network device is brought UP */ | |
5898 | + usb_set_interface(usbdev, union_header->bSlaveInterface0, | |
5899 | + !pnd->active_setting); | |
5900 | + usb_set_intfdata(intf, pnd); | |
5901 | + | |
5902 | + err = register_netdev(dev); | |
5903 | + if (err) { | |
5904 | + usb_driver_release_interface(&usbpn_driver, data_intf); | |
5905 | + goto out; | |
5906 | + } | |
5907 | + | |
5908 | + dev_dbg(&dev->dev, "USB CDC Phonet device found\n"); | |
5909 | + return 0; | |
5910 | + | |
5911 | +out: | |
5912 | + usb_set_intfdata(intf, NULL); | |
5913 | + free_netdev(dev); | |
5914 | + return err; | |
5915 | +} | |
5916 | + | |
5917 | +static void usbpn_disconnect(struct usb_interface *intf) | |
5918 | +{ | |
5919 | + struct usbpn_dev *pnd = usb_get_intfdata(intf); | |
5920 | + | |
5921 | + if (pnd->disconnected) | |
5922 | + return; | |
5923 | + | |
5924 | + pnd->disconnected = 1; | |
5925 | + usb_driver_release_interface(&usbpn_driver, | |
5926 | + (pnd->intf == intf) ? pnd->data_intf : pnd->intf); | |
5927 | + unregister_netdev(pnd->dev); | |
5928 | +} | |
5929 | + | |
5930 | +static struct usb_driver usbpn_driver = { | |
5931 | + .name = "cdc_phonet", | |
5932 | + .probe = usbpn_probe, | |
5933 | + .disconnect = usbpn_disconnect, | |
5934 | + .id_table = usbpn_ids, | |
5935 | + .disable_hub_initiated_lpm = 1, | |
5936 | +}; | |
5937 | + | |
5938 | +module_usb_driver(usbpn_driver); | |
5939 | + | |
5940 | +MODULE_AUTHOR("Remi Denis-Courmont"); | |
5941 | +MODULE_DESCRIPTION("USB CDC Phonet host interface"); | |
5942 | +MODULE_LICENSE("GPL"); | |
5943 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/cdc_subset.c backports-3.18.1-1/drivers/net/usb/cdc_subset.c | |
5944 | --- backports-3.18.1-1.org/drivers/net/usb/cdc_subset.c 1970-01-01 01:00:00.000000000 +0100 | |
5945 | +++ backports-3.18.1-1/drivers/net/usb/cdc_subset.c 2014-12-16 18:39:45.000000000 +0100 | |
5946 | @@ -0,0 +1,369 @@ | |
5947 | +/* | |
5948 | + * Simple "CDC Subset" USB Networking Links | |
5949 | + * Copyright (C) 2000-2005 by David Brownell | |
5950 | + * | |
5951 | + * This program is free software; you can redistribute it and/or modify | |
5952 | + * it under the terms of the GNU General Public License as published by | |
5953 | + * the Free Software Foundation; either version 2 of the License, or | |
5954 | + * (at your option) any later version. | |
5955 | + * | |
5956 | + * This program is distributed in the hope that it will be useful, | |
5957 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
5958 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
5959 | + * GNU General Public License for more details. | |
5960 | + * | |
5961 | + * You should have received a copy of the GNU General Public License | |
5962 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
5963 | + */ | |
5964 | + | |
5965 | +#include <linux/module.h> | |
5966 | +#include <linux/kmod.h> | |
5967 | +#include <linux/netdevice.h> | |
5968 | +#include <linux/etherdevice.h> | |
5969 | +#include <linux/ethtool.h> | |
5970 | +#include <linux/workqueue.h> | |
5971 | +#include <linux/mii.h> | |
5972 | +#include <linux/usb.h> | |
5973 | +#include <linux/usb/usbnet.h> | |
5974 | + | |
5975 | + | |
5976 | +/* | |
5977 | + * This supports simple USB network links that don't require any special | |
5978 | + * framing or hardware control operations. The protocol used here is a | |
5979 | + * strict subset of CDC Ethernet, with three basic differences reflecting | |
5980 | + * the goal that almost any hardware should run it: | |
5981 | + * | |
5982 | + * - Minimal runtime control: one interface, no altsettings, and | |
5983 | + * no vendor or class specific control requests. If a device is | |
5984 | + * configured, it is allowed to exchange packets with the host. | |
5985 | + * Fancier models would mean not working on some hardware. | |
5986 | + * | |
5987 | + * - Minimal manufacturing control: no IEEE "Organizationally | |
5988 | + * Unique ID" required, or an EEPROMs to store one. Each host uses | |
5989 | + * one random "locally assigned" Ethernet address instead, which can | |
5990 | + * of course be overridden using standard tools like "ifconfig". | |
5991 | + * (With 2^46 such addresses, same-net collisions are quite rare.) | |
5992 | + * | |
5993 | + * - There is no additional framing data for USB. Packets are written | |
5994 | + * exactly as in CDC Ethernet, starting with an Ethernet header and | |
5995 | + * terminated by a short packet. However, the host will never send a | |
5996 | + * zero length packet; some systems can't handle those robustly. | |
5997 | + * | |
5998 | + * Anything that can transmit and receive USB bulk packets can implement | |
5999 | + * this protocol. That includes both smart peripherals and quite a lot | |
6000 | + * of "host-to-host" USB cables (which embed two devices back-to-back). | |
6001 | + * | |
6002 | + * Note that although Linux may use many of those host-to-host links | |
6003 | + * with this "cdc_subset" framing, that doesn't mean there may not be a | |
6004 | + * better approach. Handling the "other end unplugs/replugs" scenario | |
6005 | + * well tends to require chip-specific vendor requests. Also, Windows | |
6006 | + * peers at the other end of host-to-host cables may expect their own | |
6007 | + * framing to be used rather than this "cdc_subset" model. | |
6008 | + */ | |
6009 | + | |
6010 | +#if defined(CONFIG_USB_EPSON2888) || defined(CONFIG_USB_ARMLINUX) | |
6011 | +/* PDA style devices are always connected if present */ | |
6012 | +static int always_connected (struct usbnet *dev) | |
6013 | +{ | |
6014 | + return 0; | |
6015 | +} | |
6016 | +#endif | |
6017 | + | |
6018 | +#ifdef CONFIG_USB_ALI_M5632 | |
6019 | +#define HAVE_HARDWARE | |
6020 | + | |
6021 | +/*------------------------------------------------------------------------- | |
6022 | + * | |
6023 | + * ALi M5632 driver ... does high speed | |
6024 | + * | |
6025 | + * NOTE that the MS-Windows drivers for this chip use some funky and | |
6026 | + * (naturally) undocumented 7-byte prefix to each packet, so this is a | |
6027 | + * case where we don't currently interoperate. Also, once you unplug | |
6028 | + * one end of the cable, you need to replug the other end too ... since | |
6029 | + * chip docs are unavailable, there's no way to reset the relevant state | |
6030 | + * short of a power cycle. | |
6031 | + * | |
6032 | + *-------------------------------------------------------------------------*/ | |
6033 | + | |
6034 | +static void m5632_recover(struct usbnet *dev) | |
6035 | +{ | |
6036 | + struct usb_device *udev = dev->udev; | |
6037 | + struct usb_interface *intf = dev->intf; | |
6038 | + int r; | |
6039 | + | |
6040 | + r = usb_lock_device_for_reset(udev, intf); | |
6041 | + if (r < 0) | |
6042 | + return; | |
6043 | + | |
6044 | + usb_reset_device(udev); | |
6045 | + usb_unlock_device(udev); | |
6046 | +} | |
6047 | + | |
6048 | +static const struct driver_info ali_m5632_info = { | |
6049 | + .description = "ALi M5632", | |
6050 | + .flags = FLAG_POINTTOPOINT, | |
6051 | + .recover = m5632_recover, | |
6052 | +}; | |
6053 | + | |
6054 | +#endif | |
6055 | + | |
6056 | +#ifdef CONFIG_USB_AN2720 | |
6057 | +#define HAVE_HARDWARE | |
6058 | + | |
6059 | +/*------------------------------------------------------------------------- | |
6060 | + * | |
6061 | + * AnchorChips 2720 driver ... http://www.cypress.com | |
6062 | + * | |
6063 | + * This doesn't seem to have a way to detect whether the peer is | |
6064 | + * connected, or need any reset handshaking. It's got pretty big | |
6065 | + * internal buffers (handles most of a frame's worth of data). | |
6066 | + * Chip data sheets don't describe any vendor control messages. | |
6067 | + * | |
6068 | + *-------------------------------------------------------------------------*/ | |
6069 | + | |
6070 | +static const struct driver_info an2720_info = { | |
6071 | + .description = "AnchorChips/Cypress 2720", | |
6072 | + .flags = FLAG_POINTTOPOINT, | |
6073 | + // no reset available! | |
6074 | + // no check_connect available! | |
6075 | + | |
6076 | + .in = 2, .out = 2, // direction distinguishes these | |
6077 | +}; | |
6078 | + | |
6079 | +#endif /* CONFIG_USB_AN2720 */ | |
6080 | + | |
6081 | +\f | |
6082 | +#ifdef CONFIG_USB_BELKIN | |
6083 | +#define HAVE_HARDWARE | |
6084 | + | |
6085 | +/*------------------------------------------------------------------------- | |
6086 | + * | |
6087 | + * Belkin F5U104 ... two NetChip 2280 devices + Atmel AVR microcontroller | |
6088 | + * | |
6089 | + * ... also two eTEK designs, including one sold as "Advance USBNET" | |
6090 | + * | |
6091 | + *-------------------------------------------------------------------------*/ | |
6092 | + | |
6093 | +static const struct driver_info belkin_info = { | |
6094 | + .description = "Belkin, eTEK, or compatible", | |
6095 | + .flags = FLAG_POINTTOPOINT, | |
6096 | +}; | |
6097 | + | |
6098 | +#endif /* CONFIG_USB_BELKIN */ | |
6099 | + | |
6100 | + | |
6101 | +\f | |
6102 | +#ifdef CONFIG_USB_EPSON2888 | |
6103 | +#define HAVE_HARDWARE | |
6104 | + | |
6105 | +/*------------------------------------------------------------------------- | |
6106 | + * | |
6107 | + * EPSON USB clients | |
6108 | + * | |
6109 | + * This is the same idea as Linux PDAs (below) except the firmware in the | |
6110 | + * device might not be Tux-powered. Epson provides reference firmware that | |
6111 | + * implements this interface. Product developers can reuse or modify that | |
6112 | + * code, such as by using their own product and vendor codes. | |
6113 | + * | |
6114 | + * Support was from Juro Bystricky <bystricky.juro@erd.epson.com> | |
6115 | + * | |
6116 | + *-------------------------------------------------------------------------*/ | |
6117 | + | |
6118 | +static const struct driver_info epson2888_info = { | |
6119 | + .description = "Epson USB Device", | |
6120 | + .check_connect = always_connected, | |
6121 | + .flags = FLAG_POINTTOPOINT, | |
6122 | + | |
6123 | + .in = 4, .out = 3, | |
6124 | +}; | |
6125 | + | |
6126 | +#endif /* CONFIG_USB_EPSON2888 */ | |
6127 | + | |
6128 | +\f | |
6129 | +/*------------------------------------------------------------------------- | |
6130 | + * | |
6131 | + * info from Jonathan McDowell <noodles@earth.li> | |
6132 | + * | |
6133 | + *-------------------------------------------------------------------------*/ | |
6134 | +#ifdef CONFIG_USB_KC2190 | |
6135 | +#define HAVE_HARDWARE | |
6136 | +static const struct driver_info kc2190_info = { | |
6137 | + .description = "KC Technology KC-190", | |
6138 | + .flags = FLAG_POINTTOPOINT, | |
6139 | +}; | |
6140 | +#endif /* CONFIG_USB_KC2190 */ | |
6141 | + | |
6142 | +\f | |
6143 | +#ifdef CONFIG_USB_ARMLINUX | |
6144 | +#define HAVE_HARDWARE | |
6145 | + | |
6146 | +/*------------------------------------------------------------------------- | |
6147 | + * | |
6148 | + * Intel's SA-1100 chip integrates basic USB support, and is used | |
6149 | + * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. | |
6150 | + * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to | |
6151 | + * network using minimal USB framing data. | |
6152 | + * | |
6153 | + * This describes the driver currently in standard ARM Linux kernels. | |
6154 | + * The Zaurus uses a different driver (see later). | |
6155 | + * | |
6156 | + * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support | |
6157 | + * and different USB endpoint numbering than the SA1100 devices. The | |
6158 | + * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 | |
6159 | + * so we rely on the endpoint descriptors. | |
6160 | + * | |
6161 | + *-------------------------------------------------------------------------*/ | |
6162 | + | |
6163 | +static const struct driver_info linuxdev_info = { | |
6164 | + .description = "Linux Device", | |
6165 | + .check_connect = always_connected, | |
6166 | + .flags = FLAG_POINTTOPOINT, | |
6167 | +}; | |
6168 | + | |
6169 | +static const struct driver_info yopy_info = { | |
6170 | + .description = "Yopy", | |
6171 | + .check_connect = always_connected, | |
6172 | + .flags = FLAG_POINTTOPOINT, | |
6173 | +}; | |
6174 | + | |
6175 | +static const struct driver_info blob_info = { | |
6176 | + .description = "Boot Loader OBject", | |
6177 | + .check_connect = always_connected, | |
6178 | + .flags = FLAG_POINTTOPOINT, | |
6179 | +}; | |
6180 | + | |
6181 | +#endif /* CONFIG_USB_ARMLINUX */ | |
6182 | + | |
6183 | +\f | |
6184 | +/*-------------------------------------------------------------------------*/ | |
6185 | + | |
6186 | +#ifndef HAVE_HARDWARE | |
6187 | +#warning You need to configure some hardware for this driver | |
6188 | +#endif | |
6189 | + | |
6190 | +/* | |
6191 | + * chip vendor names won't normally be on the cables, and | |
6192 | + * may not be on the device. | |
6193 | + */ | |
6194 | + | |
6195 | +static const struct usb_device_id products [] = { | |
6196 | + | |
6197 | +#ifdef CONFIG_USB_ALI_M5632 | |
6198 | +{ | |
6199 | + USB_DEVICE (0x0402, 0x5632), // ALi defaults | |
6200 | + .driver_info = (unsigned long) &ali_m5632_info, | |
6201 | +}, | |
6202 | +{ | |
6203 | + USB_DEVICE (0x182d,0x207c), // SiteCom CN-124 | |
6204 | + .driver_info = (unsigned long) &ali_m5632_info, | |
6205 | +}, | |
6206 | +#endif | |
6207 | + | |
6208 | +#ifdef CONFIG_USB_AN2720 | |
6209 | +{ | |
6210 | + USB_DEVICE (0x0547, 0x2720), // AnchorChips defaults | |
6211 | + .driver_info = (unsigned long) &an2720_info, | |
6212 | +}, { | |
6213 | + USB_DEVICE (0x0547, 0x2727), // Xircom PGUNET | |
6214 | + .driver_info = (unsigned long) &an2720_info, | |
6215 | +}, | |
6216 | +#endif | |
6217 | + | |
6218 | +#ifdef CONFIG_USB_BELKIN | |
6219 | +{ | |
6220 | + USB_DEVICE (0x050d, 0x0004), // Belkin | |
6221 | + .driver_info = (unsigned long) &belkin_info, | |
6222 | +}, { | |
6223 | + USB_DEVICE (0x056c, 0x8100), // eTEK | |
6224 | + .driver_info = (unsigned long) &belkin_info, | |
6225 | +}, { | |
6226 | + USB_DEVICE (0x0525, 0x9901), // Advance USBNET (eTEK) | |
6227 | + .driver_info = (unsigned long) &belkin_info, | |
6228 | +}, | |
6229 | +#endif | |
6230 | + | |
6231 | +#ifdef CONFIG_USB_EPSON2888 | |
6232 | +{ | |
6233 | + USB_DEVICE (0x0525, 0x2888), // EPSON USB client | |
6234 | + .driver_info = (unsigned long) &epson2888_info, | |
6235 | +}, | |
6236 | +#endif | |
6237 | + | |
6238 | +#ifdef CONFIG_USB_KC2190 | |
6239 | +{ | |
6240 | + USB_DEVICE (0x050f, 0x0190), // KC-190 | |
6241 | + .driver_info = (unsigned long) &kc2190_info, | |
6242 | +}, | |
6243 | +#endif | |
6244 | + | |
6245 | +#ifdef CONFIG_USB_ARMLINUX | |
6246 | +/* | |
6247 | + * SA-1100 using standard ARM Linux kernels, or compatible. | |
6248 | + * Often used when talking to Linux PDAs (iPaq, Yopy, etc). | |
6249 | + * The sa-1100 "usb-eth" driver handles the basic framing. | |
6250 | + * | |
6251 | + * PXA25x or PXA210 ... these use a "usb-eth" driver much like | |
6252 | + * the sa1100 one, but hardware uses different endpoint numbers. | |
6253 | + * | |
6254 | + * Or the Linux "Ethernet" gadget on hardware that can't talk | |
6255 | + * CDC Ethernet (e.g., no altsettings), in either of two modes: | |
6256 | + * - acting just like the old "usb-eth" firmware, though | |
6257 | + * the implementation is different | |
6258 | + * - supporting RNDIS as the first/default configuration for | |
6259 | + * MS-Windows interop; Linux needs to use the other config | |
6260 | + */ | |
6261 | +{ | |
6262 | + // 1183 = 0x049F, both used as hex values? | |
6263 | + // Compaq "Itsy" vendor/product id | |
6264 | + USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible | |
6265 | + .driver_info = (unsigned long) &linuxdev_info, | |
6266 | +}, { | |
6267 | + USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" | |
6268 | + .driver_info = (unsigned long) &yopy_info, | |
6269 | +}, { | |
6270 | + USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader | |
6271 | + .driver_info = (unsigned long) &blob_info, | |
6272 | +}, { | |
6273 | + USB_DEVICE (0x1286, 0x8001), // "blob" bootloader | |
6274 | + .driver_info = (unsigned long) &blob_info, | |
6275 | +}, { | |
6276 | + // Linux Ethernet/RNDIS gadget, mostly on PXA, second config | |
6277 | + // e.g. Gumstix, current OpenZaurus, ... or anything else | |
6278 | + // that just enables this gadget option. | |
6279 | + USB_DEVICE (0x0525, 0xa4a2), | |
6280 | + .driver_info = (unsigned long) &linuxdev_info, | |
6281 | +}, | |
6282 | +#endif | |
6283 | + | |
6284 | + { }, // END | |
6285 | +}; | |
6286 | +MODULE_DEVICE_TABLE(usb, products); | |
6287 | + | |
6288 | +/*-------------------------------------------------------------------------*/ | |
6289 | +static int dummy_prereset(struct usb_interface *intf) | |
6290 | +{ | |
6291 | + return 0; | |
6292 | +} | |
6293 | + | |
6294 | +static int dummy_postreset(struct usb_interface *intf) | |
6295 | +{ | |
6296 | + return 0; | |
6297 | +} | |
6298 | + | |
6299 | +static struct usb_driver cdc_subset_driver = { | |
6300 | + .name = "cdc_subset", | |
6301 | + .probe = usbnet_probe, | |
6302 | + .suspend = usbnet_suspend, | |
6303 | + .resume = usbnet_resume, | |
6304 | + .pre_reset = dummy_prereset, | |
6305 | + .post_reset = dummy_postreset, | |
6306 | + .disconnect = usbnet_disconnect, | |
6307 | + .id_table = products, | |
6308 | + .disable_hub_initiated_lpm = 1, | |
6309 | +}; | |
6310 | + | |
6311 | +module_usb_driver(cdc_subset_driver); | |
6312 | + | |
6313 | +MODULE_AUTHOR("David Brownell"); | |
6314 | +MODULE_DESCRIPTION("Simple 'CDC Subset' USB networking links"); | |
6315 | +MODULE_LICENSE("GPL"); | |
6316 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/cx82310_eth.c backports-3.18.1-1/drivers/net/usb/cx82310_eth.c | |
6317 | --- backports-3.18.1-1.org/drivers/net/usb/cx82310_eth.c 1970-01-01 01:00:00.000000000 +0100 | |
6318 | +++ backports-3.18.1-1/drivers/net/usb/cx82310_eth.c 2014-12-16 18:39:45.000000000 +0100 | |
6319 | @@ -0,0 +1,326 @@ | |
6320 | +/* | |
6321 | + * Driver for USB ethernet port of Conexant CX82310-based ADSL routers | |
6322 | + * Copyright (C) 2010 by Ondrej Zary | |
6323 | + * some parts inspired by the cxacru driver | |
6324 | + * | |
6325 | + * This program is free software; you can redistribute it and/or modify | |
6326 | + * it under the terms of the GNU General Public License as published by | |
6327 | + * the Free Software Foundation; either version 2 of the License, or | |
6328 | + * (at your option) any later version. | |
6329 | + * | |
6330 | + * This program is distributed in the hope that it will be useful, | |
6331 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6332 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6333 | + * GNU General Public License for more details. | |
6334 | + * | |
6335 | + * You should have received a copy of the GNU General Public License | |
6336 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
6337 | + */ | |
6338 | + | |
6339 | +#include <linux/module.h> | |
6340 | +#include <linux/netdevice.h> | |
6341 | +#include <linux/etherdevice.h> | |
6342 | +#include <linux/ethtool.h> | |
6343 | +#include <linux/workqueue.h> | |
6344 | +#include <linux/mii.h> | |
6345 | +#include <linux/usb.h> | |
6346 | +#include <linux/usb/usbnet.h> | |
6347 | + | |
6348 | +enum cx82310_cmd { | |
6349 | + CMD_START = 0x84, /* no effect? */ | |
6350 | + CMD_STOP = 0x85, /* no effect? */ | |
6351 | + CMD_GET_STATUS = 0x90, /* returns nothing? */ | |
6352 | + CMD_GET_MAC_ADDR = 0x91, /* read MAC address */ | |
6353 | + CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */ | |
6354 | + CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */ | |
6355 | +}; | |
6356 | + | |
6357 | +enum cx82310_status { | |
6358 | + STATUS_UNDEFINED, | |
6359 | + STATUS_SUCCESS, | |
6360 | + STATUS_ERROR, | |
6361 | + STATUS_UNSUPPORTED, | |
6362 | + STATUS_UNIMPLEMENTED, | |
6363 | + STATUS_PARAMETER_ERROR, | |
6364 | + STATUS_DBG_LOOPBACK, | |
6365 | +}; | |
6366 | + | |
6367 | +#define CMD_PACKET_SIZE 64 | |
6368 | +/* first command after power on can take around 8 seconds */ | |
6369 | +#define CMD_TIMEOUT 15000 | |
6370 | +#define CMD_REPLY_RETRY 5 | |
6371 | + | |
6372 | +#define CX82310_MTU 1514 | |
6373 | +#define CMD_EP 0x01 | |
6374 | + | |
6375 | +/* | |
6376 | + * execute control command | |
6377 | + * - optionally send some data (command parameters) | |
6378 | + * - optionally wait for the reply | |
6379 | + * - optionally read some data from the reply | |
6380 | + */ | |
6381 | +static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply, | |
6382 | + u8 *wdata, int wlen, u8 *rdata, int rlen) | |
6383 | +{ | |
6384 | + int actual_len, retries, ret; | |
6385 | + struct usb_device *udev = dev->udev; | |
6386 | + u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL); | |
6387 | + | |
6388 | + if (!buf) | |
6389 | + return -ENOMEM; | |
6390 | + | |
6391 | + /* create command packet */ | |
6392 | + buf[0] = cmd; | |
6393 | + if (wdata) | |
6394 | + memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4)); | |
6395 | + | |
6396 | + /* send command packet */ | |
6397 | + ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf, | |
6398 | + CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT); | |
6399 | + if (ret < 0) { | |
6400 | + dev_err(&dev->udev->dev, "send command %#x: error %d\n", | |
6401 | + cmd, ret); | |
6402 | + goto end; | |
6403 | + } | |
6404 | + | |
6405 | + if (reply) { | |
6406 | + /* wait for reply, retry if it's empty */ | |
6407 | + for (retries = 0; retries < CMD_REPLY_RETRY; retries++) { | |
6408 | + ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP), | |
6409 | + buf, CMD_PACKET_SIZE, &actual_len, | |
6410 | + CMD_TIMEOUT); | |
6411 | + if (ret < 0) { | |
6412 | + dev_err(&dev->udev->dev, | |
6413 | + "reply receive error %d\n", ret); | |
6414 | + goto end; | |
6415 | + } | |
6416 | + if (actual_len > 0) | |
6417 | + break; | |
6418 | + } | |
6419 | + if (actual_len == 0) { | |
6420 | + dev_err(&dev->udev->dev, "no reply to command %#x\n", | |
6421 | + cmd); | |
6422 | + ret = -EIO; | |
6423 | + goto end; | |
6424 | + } | |
6425 | + if (buf[0] != cmd) { | |
6426 | + dev_err(&dev->udev->dev, | |
6427 | + "got reply to command %#x, expected: %#x\n", | |
6428 | + buf[0], cmd); | |
6429 | + ret = -EIO; | |
6430 | + goto end; | |
6431 | + } | |
6432 | + if (buf[1] != STATUS_SUCCESS) { | |
6433 | + dev_err(&dev->udev->dev, "command %#x failed: %#x\n", | |
6434 | + cmd, buf[1]); | |
6435 | + ret = -EIO; | |
6436 | + goto end; | |
6437 | + } | |
6438 | + if (rdata) | |
6439 | + memcpy(rdata, buf + 4, | |
6440 | + min_t(int, rlen, CMD_PACKET_SIZE - 4)); | |
6441 | + } | |
6442 | +end: | |
6443 | + kfree(buf); | |
6444 | + return ret; | |
6445 | +} | |
6446 | + | |
6447 | +#define partial_len data[0] /* length of partial packet data */ | |
6448 | +#define partial_rem data[1] /* remaining (missing) data length */ | |
6449 | +#define partial_data data[2] /* partial packet data */ | |
6450 | + | |
6451 | +static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf) | |
6452 | +{ | |
6453 | + int ret; | |
6454 | + char buf[15]; | |
6455 | + struct usb_device *udev = dev->udev; | |
6456 | + | |
6457 | + /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */ | |
6458 | + if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0 | |
6459 | + && strcmp(buf, "USB NET CARD")) { | |
6460 | + dev_info(&udev->dev, "ignoring: probably an ADSL modem\n"); | |
6461 | + return -ENODEV; | |
6462 | + } | |
6463 | + | |
6464 | + ret = usbnet_get_endpoints(dev, intf); | |
6465 | + if (ret) | |
6466 | + return ret; | |
6467 | + | |
6468 | + /* | |
6469 | + * this must not include ethernet header as the device can send partial | |
6470 | + * packets with no header (and sometimes even empty URBs) | |
6471 | + */ | |
6472 | + dev->net->hard_header_len = 0; | |
6473 | + /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */ | |
6474 | + dev->hard_mtu = CX82310_MTU + 2; | |
6475 | + /* we can receive URBs up to 4KB from the device */ | |
6476 | + dev->rx_urb_size = 4096; | |
6477 | + | |
6478 | + dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL); | |
6479 | + if (!dev->partial_data) | |
6480 | + return -ENOMEM; | |
6481 | + | |
6482 | + /* enable ethernet mode (?) */ | |
6483 | + ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0); | |
6484 | + if (ret) { | |
6485 | + dev_err(&udev->dev, "unable to enable ethernet mode: %d\n", | |
6486 | + ret); | |
6487 | + goto err; | |
6488 | + } | |
6489 | + | |
6490 | + /* get the MAC address */ | |
6491 | + ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0, | |
6492 | + dev->net->dev_addr, ETH_ALEN); | |
6493 | + if (ret) { | |
6494 | + dev_err(&udev->dev, "unable to read MAC address: %d\n", ret); | |
6495 | + goto err; | |
6496 | + } | |
6497 | + | |
6498 | + /* start (does not seem to have any effect?) */ | |
6499 | + ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0); | |
6500 | + if (ret) | |
6501 | + goto err; | |
6502 | + | |
6503 | + return 0; | |
6504 | +err: | |
6505 | + kfree((void *)dev->partial_data); | |
6506 | + return ret; | |
6507 | +} | |
6508 | + | |
6509 | +static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf) | |
6510 | +{ | |
6511 | + kfree((void *)dev->partial_data); | |
6512 | +} | |
6513 | + | |
6514 | +/* | |
6515 | + * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte | |
6516 | + * packet length at the beginning. | |
6517 | + * The last packet might be incomplete (when it crosses the 4KB URB size), | |
6518 | + * continuing in the next skb (without any headers). | |
6519 | + * If a packet has odd length, there is one extra byte at the end (before next | |
6520 | + * packet or at the end of the URB). | |
6521 | + */ | |
6522 | +static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
6523 | +{ | |
6524 | + int len; | |
6525 | + struct sk_buff *skb2; | |
6526 | + | |
6527 | + /* | |
6528 | + * If the last skb ended with an incomplete packet, this skb contains | |
6529 | + * end of that packet at the beginning. | |
6530 | + */ | |
6531 | + if (dev->partial_rem) { | |
6532 | + len = dev->partial_len + dev->partial_rem; | |
6533 | + skb2 = alloc_skb(len, GFP_ATOMIC); | |
6534 | + if (!skb2) | |
6535 | + return 0; | |
6536 | + skb_put(skb2, len); | |
6537 | + memcpy(skb2->data, (void *)dev->partial_data, | |
6538 | + dev->partial_len); | |
6539 | + memcpy(skb2->data + dev->partial_len, skb->data, | |
6540 | + dev->partial_rem); | |
6541 | + usbnet_skb_return(dev, skb2); | |
6542 | + skb_pull(skb, (dev->partial_rem + 1) & ~1); | |
6543 | + dev->partial_rem = 0; | |
6544 | + if (skb->len < 2) | |
6545 | + return 1; | |
6546 | + } | |
6547 | + | |
6548 | + /* a skb can contain multiple packets */ | |
6549 | + while (skb->len > 1) { | |
6550 | + /* first two bytes are packet length */ | |
6551 | + len = skb->data[0] | (skb->data[1] << 8); | |
6552 | + skb_pull(skb, 2); | |
6553 | + | |
6554 | + /* if last packet in the skb, let usbnet to process it */ | |
6555 | + if (len == skb->len || len + 1 == skb->len) { | |
6556 | + skb_trim(skb, len); | |
6557 | + break; | |
6558 | + } | |
6559 | + | |
6560 | + if (len > CX82310_MTU) { | |
6561 | + dev_err(&dev->udev->dev, "RX packet too long: %d B\n", | |
6562 | + len); | |
6563 | + return 0; | |
6564 | + } | |
6565 | + | |
6566 | + /* incomplete packet, save it for the next skb */ | |
6567 | + if (len > skb->len) { | |
6568 | + dev->partial_len = skb->len; | |
6569 | + dev->partial_rem = len - skb->len; | |
6570 | + memcpy((void *)dev->partial_data, skb->data, | |
6571 | + dev->partial_len); | |
6572 | + skb_pull(skb, skb->len); | |
6573 | + break; | |
6574 | + } | |
6575 | + | |
6576 | + skb2 = alloc_skb(len, GFP_ATOMIC); | |
6577 | + if (!skb2) | |
6578 | + return 0; | |
6579 | + skb_put(skb2, len); | |
6580 | + memcpy(skb2->data, skb->data, len); | |
6581 | + /* process the packet */ | |
6582 | + usbnet_skb_return(dev, skb2); | |
6583 | + | |
6584 | + skb_pull(skb, (len + 1) & ~1); | |
6585 | + } | |
6586 | + | |
6587 | + /* let usbnet process the last packet */ | |
6588 | + return 1; | |
6589 | +} | |
6590 | + | |
6591 | +/* TX is easy, just add 2 bytes of length at the beginning */ | |
6592 | +static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
6593 | + gfp_t flags) | |
6594 | +{ | |
6595 | + int len = skb->len; | |
6596 | + | |
6597 | + if (skb_headroom(skb) < 2) { | |
6598 | + struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags); | |
6599 | + dev_kfree_skb_any(skb); | |
6600 | + skb = skb2; | |
6601 | + if (!skb) | |
6602 | + return NULL; | |
6603 | + } | |
6604 | + skb_push(skb, 2); | |
6605 | + | |
6606 | + skb->data[0] = len; | |
6607 | + skb->data[1] = len >> 8; | |
6608 | + | |
6609 | + return skb; | |
6610 | +} | |
6611 | + | |
6612 | + | |
6613 | +static const struct driver_info cx82310_info = { | |
6614 | + .description = "Conexant CX82310 USB ethernet", | |
6615 | + .flags = FLAG_ETHER, | |
6616 | + .bind = cx82310_bind, | |
6617 | + .unbind = cx82310_unbind, | |
6618 | + .rx_fixup = cx82310_rx_fixup, | |
6619 | + .tx_fixup = cx82310_tx_fixup, | |
6620 | +}; | |
6621 | + | |
6622 | +static const struct usb_device_id products[] = { | |
6623 | + { | |
6624 | + USB_DEVICE_AND_INTERFACE_INFO(0x0572, 0xcb01, 0xff, 0, 0), | |
6625 | + .driver_info = (unsigned long) &cx82310_info | |
6626 | + }, | |
6627 | + { }, | |
6628 | +}; | |
6629 | +MODULE_DEVICE_TABLE(usb, products); | |
6630 | + | |
6631 | +static struct usb_driver cx82310_driver = { | |
6632 | + .name = "cx82310_eth", | |
6633 | + .id_table = products, | |
6634 | + .probe = usbnet_probe, | |
6635 | + .disconnect = usbnet_disconnect, | |
6636 | + .suspend = usbnet_suspend, | |
6637 | + .resume = usbnet_resume, | |
6638 | + .disable_hub_initiated_lpm = 1, | |
6639 | +}; | |
6640 | + | |
6641 | +module_usb_driver(cx82310_driver); | |
6642 | + | |
6643 | +MODULE_AUTHOR("Ondrej Zary"); | |
6644 | +MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver"); | |
6645 | +MODULE_LICENSE("GPL"); | |
6646 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/dm9601.c backports-3.18.1-1/drivers/net/usb/dm9601.c | |
6647 | --- backports-3.18.1-1.org/drivers/net/usb/dm9601.c 1970-01-01 01:00:00.000000000 +0100 | |
6648 | +++ backports-3.18.1-1/drivers/net/usb/dm9601.c 2014-12-16 18:39:45.000000000 +0100 | |
6649 | @@ -0,0 +1,647 @@ | |
6650 | +/* | |
6651 | + * Davicom DM96xx USB 10/100Mbps ethernet devices | |
6652 | + * | |
6653 | + * Peter Korsgaard <jacmet@sunsite.dk> | |
6654 | + * | |
6655 | + * This file is licensed under the terms of the GNU General Public License | |
6656 | + * version 2. This program is licensed "as is" without any warranty of any | |
6657 | + * kind, whether express or implied. | |
6658 | + */ | |
6659 | + | |
6660 | +//#define DEBUG | |
6661 | + | |
6662 | +#include <linux/module.h> | |
6663 | +#include <linux/sched.h> | |
6664 | +#include <linux/stddef.h> | |
6665 | +#include <linux/netdevice.h> | |
6666 | +#include <linux/etherdevice.h> | |
6667 | +#include <linux/ethtool.h> | |
6668 | +#include <linux/mii.h> | |
6669 | +#include <linux/usb.h> | |
6670 | +#include <linux/crc32.h> | |
6671 | +#include <linux/usb/usbnet.h> | |
6672 | +#include <linux/slab.h> | |
6673 | + | |
6674 | +/* datasheet: | |
6675 | + http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf | |
6676 | +*/ | |
6677 | + | |
6678 | +/* control requests */ | |
6679 | +#define DM_READ_REGS 0x00 | |
6680 | +#define DM_WRITE_REGS 0x01 | |
6681 | +#define DM_READ_MEMS 0x02 | |
6682 | +#define DM_WRITE_REG 0x03 | |
6683 | +#define DM_WRITE_MEMS 0x05 | |
6684 | +#define DM_WRITE_MEM 0x07 | |
6685 | + | |
6686 | +/* registers */ | |
6687 | +#define DM_NET_CTRL 0x00 | |
6688 | +#define DM_RX_CTRL 0x05 | |
6689 | +#define DM_SHARED_CTRL 0x0b | |
6690 | +#define DM_SHARED_ADDR 0x0c | |
6691 | +#define DM_SHARED_DATA 0x0d /* low + high */ | |
6692 | +#define DM_PHY_ADDR 0x10 /* 6 bytes */ | |
6693 | +#define DM_MCAST_ADDR 0x16 /* 8 bytes */ | |
6694 | +#define DM_GPR_CTRL 0x1e | |
6695 | +#define DM_GPR_DATA 0x1f | |
6696 | +#define DM_CHIP_ID 0x2c | |
6697 | +#define DM_MODE_CTRL 0x91 /* only on dm9620 */ | |
6698 | + | |
6699 | +/* chip id values */ | |
6700 | +#define ID_DM9601 0 | |
6701 | +#define ID_DM9620 1 | |
6702 | + | |
6703 | +#define DM_MAX_MCAST 64 | |
6704 | +#define DM_MCAST_SIZE 8 | |
6705 | +#define DM_EEPROM_LEN 256 | |
6706 | +#define DM_TX_OVERHEAD 2 /* 2 byte header */ | |
6707 | +#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ | |
6708 | +#define DM_TIMEOUT 1000 | |
6709 | + | |
6710 | +static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) | |
6711 | +{ | |
6712 | + int err; | |
6713 | + err = usbnet_read_cmd(dev, DM_READ_REGS, | |
6714 | + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
6715 | + 0, reg, data, length); | |
6716 | + if(err != length && err >= 0) | |
6717 | + err = -EINVAL; | |
6718 | + return err; | |
6719 | +} | |
6720 | + | |
6721 | +static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) | |
6722 | +{ | |
6723 | + return dm_read(dev, reg, 1, value); | |
6724 | +} | |
6725 | + | |
6726 | +static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) | |
6727 | +{ | |
6728 | + int err; | |
6729 | + err = usbnet_write_cmd(dev, DM_WRITE_REGS, | |
6730 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
6731 | + 0, reg, data, length); | |
6732 | + | |
6733 | + if (err >= 0 && err < length) | |
6734 | + err = -EINVAL; | |
6735 | + return err; | |
6736 | +} | |
6737 | + | |
6738 | +static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) | |
6739 | +{ | |
6740 | + return usbnet_write_cmd(dev, DM_WRITE_REG, | |
6741 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
6742 | + value, reg, NULL, 0); | |
6743 | +} | |
6744 | + | |
6745 | +static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) | |
6746 | +{ | |
6747 | + usbnet_write_cmd_async(dev, DM_WRITE_REGS, | |
6748 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
6749 | + 0, reg, data, length); | |
6750 | +} | |
6751 | + | |
6752 | +static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) | |
6753 | +{ | |
6754 | + usbnet_write_cmd_async(dev, DM_WRITE_REG, | |
6755 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
6756 | + value, reg, NULL, 0); | |
6757 | +} | |
6758 | + | |
6759 | +static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value) | |
6760 | +{ | |
6761 | + int ret, i; | |
6762 | + | |
6763 | + mutex_lock(&dev->phy_mutex); | |
6764 | + | |
6765 | + dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); | |
6766 | + dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4); | |
6767 | + | |
6768 | + for (i = 0; i < DM_TIMEOUT; i++) { | |
6769 | + u8 tmp = 0; | |
6770 | + | |
6771 | + udelay(1); | |
6772 | + ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); | |
6773 | + if (ret < 0) | |
6774 | + goto out; | |
6775 | + | |
6776 | + /* ready */ | |
6777 | + if ((tmp & 1) == 0) | |
6778 | + break; | |
6779 | + } | |
6780 | + | |
6781 | + if (i == DM_TIMEOUT) { | |
6782 | + netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom"); | |
6783 | + ret = -EIO; | |
6784 | + goto out; | |
6785 | + } | |
6786 | + | |
6787 | + dm_write_reg(dev, DM_SHARED_CTRL, 0x0); | |
6788 | + ret = dm_read(dev, DM_SHARED_DATA, 2, value); | |
6789 | + | |
6790 | + netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", | |
6791 | + phy, reg, *value, ret); | |
6792 | + | |
6793 | + out: | |
6794 | + mutex_unlock(&dev->phy_mutex); | |
6795 | + return ret; | |
6796 | +} | |
6797 | + | |
6798 | +static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 value) | |
6799 | +{ | |
6800 | + int ret, i; | |
6801 | + | |
6802 | + mutex_lock(&dev->phy_mutex); | |
6803 | + | |
6804 | + ret = dm_write(dev, DM_SHARED_DATA, 2, &value); | |
6805 | + if (ret < 0) | |
6806 | + goto out; | |
6807 | + | |
6808 | + dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); | |
6809 | + dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12); | |
6810 | + | |
6811 | + for (i = 0; i < DM_TIMEOUT; i++) { | |
6812 | + u8 tmp = 0; | |
6813 | + | |
6814 | + udelay(1); | |
6815 | + ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); | |
6816 | + if (ret < 0) | |
6817 | + goto out; | |
6818 | + | |
6819 | + /* ready */ | |
6820 | + if ((tmp & 1) == 0) | |
6821 | + break; | |
6822 | + } | |
6823 | + | |
6824 | + if (i == DM_TIMEOUT) { | |
6825 | + netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom"); | |
6826 | + ret = -EIO; | |
6827 | + goto out; | |
6828 | + } | |
6829 | + | |
6830 | + dm_write_reg(dev, DM_SHARED_CTRL, 0x0); | |
6831 | + | |
6832 | +out: | |
6833 | + mutex_unlock(&dev->phy_mutex); | |
6834 | + return ret; | |
6835 | +} | |
6836 | + | |
6837 | +static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) | |
6838 | +{ | |
6839 | + return dm_read_shared_word(dev, 0, offset, value); | |
6840 | +} | |
6841 | + | |
6842 | + | |
6843 | + | |
6844 | +static int dm9601_get_eeprom_len(struct net_device *dev) | |
6845 | +{ | |
6846 | + return DM_EEPROM_LEN; | |
6847 | +} | |
6848 | + | |
6849 | +static int dm9601_get_eeprom(struct net_device *net, | |
6850 | + struct ethtool_eeprom *eeprom, u8 * data) | |
6851 | +{ | |
6852 | + struct usbnet *dev = netdev_priv(net); | |
6853 | + __le16 *ebuf = (__le16 *) data; | |
6854 | + int i; | |
6855 | + | |
6856 | + /* access is 16bit */ | |
6857 | + if ((eeprom->offset % 2) || (eeprom->len % 2)) | |
6858 | + return -EINVAL; | |
6859 | + | |
6860 | + for (i = 0; i < eeprom->len / 2; i++) { | |
6861 | + if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i, | |
6862 | + &ebuf[i]) < 0) | |
6863 | + return -EINVAL; | |
6864 | + } | |
6865 | + return 0; | |
6866 | +} | |
6867 | + | |
6868 | +static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc) | |
6869 | +{ | |
6870 | + struct usbnet *dev = netdev_priv(netdev); | |
6871 | + | |
6872 | + __le16 res; | |
6873 | + | |
6874 | + if (phy_id) { | |
6875 | + netdev_dbg(dev->net, "Only internal phy supported\n"); | |
6876 | + return 0; | |
6877 | + } | |
6878 | + | |
6879 | + dm_read_shared_word(dev, 1, loc, &res); | |
6880 | + | |
6881 | + netdev_dbg(dev->net, | |
6882 | + "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | |
6883 | + phy_id, loc, le16_to_cpu(res)); | |
6884 | + | |
6885 | + return le16_to_cpu(res); | |
6886 | +} | |
6887 | + | |
6888 | +static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc, | |
6889 | + int val) | |
6890 | +{ | |
6891 | + struct usbnet *dev = netdev_priv(netdev); | |
6892 | + __le16 res = cpu_to_le16(val); | |
6893 | + | |
6894 | + if (phy_id) { | |
6895 | + netdev_dbg(dev->net, "Only internal phy supported\n"); | |
6896 | + return; | |
6897 | + } | |
6898 | + | |
6899 | + netdev_dbg(dev->net, "dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | |
6900 | + phy_id, loc, val); | |
6901 | + | |
6902 | + dm_write_shared_word(dev, 1, loc, res); | |
6903 | +} | |
6904 | + | |
6905 | +static void dm9601_get_drvinfo(struct net_device *net, | |
6906 | + struct ethtool_drvinfo *info) | |
6907 | +{ | |
6908 | + /* Inherit standard device info */ | |
6909 | + usbnet_get_drvinfo(net, info); | |
6910 | + info->eedump_len = DM_EEPROM_LEN; | |
6911 | +} | |
6912 | + | |
6913 | +static u32 dm9601_get_link(struct net_device *net) | |
6914 | +{ | |
6915 | + struct usbnet *dev = netdev_priv(net); | |
6916 | + | |
6917 | + return mii_link_ok(&dev->mii); | |
6918 | +} | |
6919 | + | |
6920 | +static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
6921 | +{ | |
6922 | + struct usbnet *dev = netdev_priv(net); | |
6923 | + | |
6924 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
6925 | +} | |
6926 | + | |
6927 | +static const struct ethtool_ops dm9601_ethtool_ops = { | |
6928 | + .get_drvinfo = dm9601_get_drvinfo, | |
6929 | + .get_link = dm9601_get_link, | |
6930 | + .get_msglevel = usbnet_get_msglevel, | |
6931 | + .set_msglevel = usbnet_set_msglevel, | |
6932 | + .get_eeprom_len = dm9601_get_eeprom_len, | |
6933 | + .get_eeprom = dm9601_get_eeprom, | |
6934 | + .get_settings = usbnet_get_settings, | |
6935 | + .set_settings = usbnet_set_settings, | |
6936 | + .nway_reset = usbnet_nway_reset, | |
6937 | +}; | |
6938 | + | |
6939 | +static void dm9601_set_multicast(struct net_device *net) | |
6940 | +{ | |
6941 | + struct usbnet *dev = netdev_priv(net); | |
6942 | + /* We use the 20 byte dev->data for our 8 byte filter buffer | |
6943 | + * to avoid allocating memory that is tricky to free later */ | |
6944 | + u8 *hashes = (u8 *) & dev->data; | |
6945 | + u8 rx_ctl = 0x31; | |
6946 | + | |
6947 | + memset(hashes, 0x00, DM_MCAST_SIZE); | |
6948 | + hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ | |
6949 | + | |
6950 | + if (net->flags & IFF_PROMISC) { | |
6951 | + rx_ctl |= 0x02; | |
6952 | + } else if (net->flags & IFF_ALLMULTI || | |
6953 | + netdev_mc_count(net) > DM_MAX_MCAST) { | |
6954 | + rx_ctl |= 0x08; | |
6955 | + } else if (!netdev_mc_empty(net)) { | |
6956 | + struct netdev_hw_addr *ha; | |
6957 | + | |
6958 | + netdev_for_each_mc_addr(ha, net) { | |
6959 | + u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
6960 | + hashes[crc >> 3] |= 1 << (crc & 0x7); | |
6961 | + } | |
6962 | + } | |
6963 | + | |
6964 | + dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); | |
6965 | + dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); | |
6966 | +} | |
6967 | + | |
6968 | +static void __dm9601_set_mac_address(struct usbnet *dev) | |
6969 | +{ | |
6970 | + dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); | |
6971 | +} | |
6972 | + | |
6973 | +static int dm9601_set_mac_address(struct net_device *net, void *p) | |
6974 | +{ | |
6975 | + struct sockaddr *addr = p; | |
6976 | + struct usbnet *dev = netdev_priv(net); | |
6977 | + | |
6978 | + if (!is_valid_ether_addr(addr->sa_data)) { | |
6979 | + dev_err(&net->dev, "not setting invalid mac address %pM\n", | |
6980 | + addr->sa_data); | |
6981 | + return -EINVAL; | |
6982 | + } | |
6983 | + | |
6984 | + memcpy(net->dev_addr, addr->sa_data, net->addr_len); | |
6985 | + __dm9601_set_mac_address(dev); | |
6986 | + | |
6987 | + return 0; | |
6988 | +} | |
6989 | + | |
6990 | +static const struct net_device_ops dm9601_netdev_ops = { | |
6991 | + .ndo_open = usbnet_open, | |
6992 | + .ndo_stop = usbnet_stop, | |
6993 | + .ndo_start_xmit = usbnet_start_xmit, | |
6994 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
6995 | + .ndo_change_mtu = usbnet_change_mtu, | |
6996 | + .ndo_validate_addr = eth_validate_addr, | |
6997 | + .ndo_do_ioctl = dm9601_ioctl, | |
6998 | + .ndo_set_rx_mode = dm9601_set_multicast, | |
6999 | + .ndo_set_mac_address = dm9601_set_mac_address, | |
7000 | +}; | |
7001 | + | |
7002 | +static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) | |
7003 | +{ | |
7004 | + int ret; | |
7005 | + u8 mac[ETH_ALEN], id; | |
7006 | + | |
7007 | + ret = usbnet_get_endpoints(dev, intf); | |
7008 | + if (ret) | |
7009 | + goto out; | |
7010 | + | |
7011 | + dev->net->netdev_ops = &dm9601_netdev_ops; | |
7012 | + dev->net->ethtool_ops = &dm9601_ethtool_ops; | |
7013 | + dev->net->hard_header_len += DM_TX_OVERHEAD; | |
7014 | + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | |
7015 | + | |
7016 | + /* dm9620/21a require room for 4 byte padding, even in dm9601 | |
7017 | + * mode, so we need +1 to be able to receive full size | |
7018 | + * ethernet frames. | |
7019 | + */ | |
7020 | + dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1; | |
7021 | + | |
7022 | + dev->mii.dev = dev->net; | |
7023 | + dev->mii.mdio_read = dm9601_mdio_read; | |
7024 | + dev->mii.mdio_write = dm9601_mdio_write; | |
7025 | + dev->mii.phy_id_mask = 0x1f; | |
7026 | + dev->mii.reg_num_mask = 0x1f; | |
7027 | + | |
7028 | + /* reset */ | |
7029 | + dm_write_reg(dev, DM_NET_CTRL, 1); | |
7030 | + udelay(20); | |
7031 | + | |
7032 | + /* read MAC */ | |
7033 | + if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) { | |
7034 | + printk(KERN_ERR "Error reading MAC address\n"); | |
7035 | + ret = -ENODEV; | |
7036 | + goto out; | |
7037 | + } | |
7038 | + | |
7039 | + /* | |
7040 | + * Overwrite the auto-generated address only with good ones. | |
7041 | + */ | |
7042 | + if (is_valid_ether_addr(mac)) | |
7043 | + memcpy(dev->net->dev_addr, mac, ETH_ALEN); | |
7044 | + else { | |
7045 | + printk(KERN_WARNING | |
7046 | + "dm9601: No valid MAC address in EEPROM, using %pM\n", | |
7047 | + dev->net->dev_addr); | |
7048 | + __dm9601_set_mac_address(dev); | |
7049 | + } | |
7050 | + | |
7051 | + if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) { | |
7052 | + netdev_err(dev->net, "Error reading chip ID\n"); | |
7053 | + ret = -ENODEV; | |
7054 | + goto out; | |
7055 | + } | |
7056 | + | |
7057 | + /* put dm9620 devices in dm9601 mode */ | |
7058 | + if (id == ID_DM9620) { | |
7059 | + u8 mode; | |
7060 | + | |
7061 | + if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) { | |
7062 | + netdev_err(dev->net, "Error reading MODE_CTRL\n"); | |
7063 | + ret = -ENODEV; | |
7064 | + goto out; | |
7065 | + } | |
7066 | + dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f); | |
7067 | + } | |
7068 | + | |
7069 | + /* power up phy */ | |
7070 | + dm_write_reg(dev, DM_GPR_CTRL, 1); | |
7071 | + dm_write_reg(dev, DM_GPR_DATA, 0); | |
7072 | + | |
7073 | + /* receive broadcast packets */ | |
7074 | + dm9601_set_multicast(dev->net); | |
7075 | + | |
7076 | + dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
7077 | + dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
7078 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | |
7079 | + mii_nway_restart(&dev->mii); | |
7080 | + | |
7081 | +out: | |
7082 | + return ret; | |
7083 | +} | |
7084 | + | |
7085 | +static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
7086 | +{ | |
7087 | + u8 status; | |
7088 | + int len; | |
7089 | + | |
7090 | + /* format: | |
7091 | + b1: rx status | |
7092 | + b2: packet length (incl crc) low | |
7093 | + b3: packet length (incl crc) high | |
7094 | + b4..n-4: packet data | |
7095 | + bn-3..bn: ethernet crc | |
7096 | + */ | |
7097 | + | |
7098 | + if (unlikely(skb->len < DM_RX_OVERHEAD)) { | |
7099 | + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); | |
7100 | + return 0; | |
7101 | + } | |
7102 | + | |
7103 | + status = skb->data[0]; | |
7104 | + len = (skb->data[1] | (skb->data[2] << 8)) - 4; | |
7105 | + | |
7106 | + if (unlikely(status & 0xbf)) { | |
7107 | + if (status & 0x01) dev->net->stats.rx_fifo_errors++; | |
7108 | + if (status & 0x02) dev->net->stats.rx_crc_errors++; | |
7109 | + if (status & 0x04) dev->net->stats.rx_frame_errors++; | |
7110 | + if (status & 0x20) dev->net->stats.rx_missed_errors++; | |
7111 | + if (status & 0x90) dev->net->stats.rx_length_errors++; | |
7112 | + return 0; | |
7113 | + } | |
7114 | + | |
7115 | + skb_pull(skb, 3); | |
7116 | + skb_trim(skb, len); | |
7117 | + | |
7118 | + return 1; | |
7119 | +} | |
7120 | + | |
7121 | +static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
7122 | + gfp_t flags) | |
7123 | +{ | |
7124 | + int len, pad; | |
7125 | + | |
7126 | + /* format: | |
7127 | + b1: packet length low | |
7128 | + b2: packet length high | |
7129 | + b3..n: packet data | |
7130 | + */ | |
7131 | + | |
7132 | + len = skb->len + DM_TX_OVERHEAD; | |
7133 | + | |
7134 | + /* workaround for dm962x errata with tx fifo getting out of | |
7135 | + * sync if a USB bulk transfer retry happens right after a | |
7136 | + * packet with odd / maxpacket length by adding up to 3 bytes | |
7137 | + * padding. | |
7138 | + */ | |
7139 | + while ((len & 1) || !(len % dev->maxpacket)) | |
7140 | + len++; | |
7141 | + | |
7142 | + len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */ | |
7143 | + pad = len - skb->len; | |
7144 | + | |
7145 | + if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) { | |
7146 | + struct sk_buff *skb2; | |
7147 | + | |
7148 | + skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags); | |
7149 | + dev_kfree_skb_any(skb); | |
7150 | + skb = skb2; | |
7151 | + if (!skb) | |
7152 | + return NULL; | |
7153 | + } | |
7154 | + | |
7155 | + __skb_push(skb, DM_TX_OVERHEAD); | |
7156 | + | |
7157 | + if (pad) { | |
7158 | + memset(skb->data + skb->len, 0, pad); | |
7159 | + __skb_put(skb, pad); | |
7160 | + } | |
7161 | + | |
7162 | + skb->data[0] = len; | |
7163 | + skb->data[1] = len >> 8; | |
7164 | + | |
7165 | + return skb; | |
7166 | +} | |
7167 | + | |
7168 | +static void dm9601_status(struct usbnet *dev, struct urb *urb) | |
7169 | +{ | |
7170 | + int link; | |
7171 | + u8 *buf; | |
7172 | + | |
7173 | + /* format: | |
7174 | + b0: net status | |
7175 | + b1: tx status 1 | |
7176 | + b2: tx status 2 | |
7177 | + b3: rx status | |
7178 | + b4: rx overflow | |
7179 | + b5: rx count | |
7180 | + b6: tx count | |
7181 | + b7: gpr | |
7182 | + */ | |
7183 | + | |
7184 | + if (urb->actual_length < 8) | |
7185 | + return; | |
7186 | + | |
7187 | + buf = urb->transfer_buffer; | |
7188 | + | |
7189 | + link = !!(buf[0] & 0x40); | |
7190 | + if (netif_carrier_ok(dev->net) != link) { | |
7191 | + usbnet_link_change(dev, link, 1); | |
7192 | + netdev_dbg(dev->net, "Link Status is: %d\n", link); | |
7193 | + } | |
7194 | +} | |
7195 | + | |
7196 | +static int dm9601_link_reset(struct usbnet *dev) | |
7197 | +{ | |
7198 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
7199 | + | |
7200 | + mii_check_media(&dev->mii, 1, 1); | |
7201 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
7202 | + | |
7203 | + netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", | |
7204 | + ethtool_cmd_speed(&ecmd), ecmd.duplex); | |
7205 | + | |
7206 | + return 0; | |
7207 | +} | |
7208 | + | |
7209 | +static const struct driver_info dm9601_info = { | |
7210 | + .description = "Davicom DM96xx USB 10/100 Ethernet", | |
7211 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
7212 | + .bind = dm9601_bind, | |
7213 | + .rx_fixup = dm9601_rx_fixup, | |
7214 | + .tx_fixup = dm9601_tx_fixup, | |
7215 | + .status = dm9601_status, | |
7216 | + .link_reset = dm9601_link_reset, | |
7217 | + .reset = dm9601_link_reset, | |
7218 | +}; | |
7219 | + | |
7220 | +static const struct usb_device_id products[] = { | |
7221 | + { | |
7222 | + USB_DEVICE(0x07aa, 0x9601), /* Corega FEther USB-TXC */ | |
7223 | + .driver_info = (unsigned long)&dm9601_info, | |
7224 | + }, | |
7225 | + { | |
7226 | + USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */ | |
7227 | + .driver_info = (unsigned long)&dm9601_info, | |
7228 | + }, | |
7229 | + { | |
7230 | + USB_DEVICE(0x0a46, 0x6688), /* ZT6688 USB NIC */ | |
7231 | + .driver_info = (unsigned long)&dm9601_info, | |
7232 | + }, | |
7233 | + { | |
7234 | + USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */ | |
7235 | + .driver_info = (unsigned long)&dm9601_info, | |
7236 | + }, | |
7237 | + { | |
7238 | + USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */ | |
7239 | + .driver_info = (unsigned long)&dm9601_info, | |
7240 | + }, | |
7241 | + { | |
7242 | + USB_DEVICE(0x0a47, 0x9601), /* Hirose USB-100 */ | |
7243 | + .driver_info = (unsigned long)&dm9601_info, | |
7244 | + }, | |
7245 | + { | |
7246 | + USB_DEVICE(0x0fe6, 0x8101), /* DM9601 USB to Fast Ethernet Adapter */ | |
7247 | + .driver_info = (unsigned long)&dm9601_info, | |
7248 | + }, | |
7249 | + { | |
7250 | + USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */ | |
7251 | + .driver_info = (unsigned long)&dm9601_info, | |
7252 | + }, | |
7253 | + { | |
7254 | + USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ | |
7255 | + .driver_info = (unsigned long)&dm9601_info, | |
7256 | + }, | |
7257 | + { | |
7258 | + USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */ | |
7259 | + .driver_info = (unsigned long)&dm9601_info, | |
7260 | + }, | |
7261 | + { | |
7262 | + USB_DEVICE(0x0a46, 0x9621), /* DM9621A USB to Fast Ethernet Adapter */ | |
7263 | + .driver_info = (unsigned long)&dm9601_info, | |
7264 | + }, | |
7265 | + { | |
7266 | + USB_DEVICE(0x0a46, 0x9622), /* DM9622 USB to Fast Ethernet Adapter */ | |
7267 | + .driver_info = (unsigned long)&dm9601_info, | |
7268 | + }, | |
7269 | + { | |
7270 | + USB_DEVICE(0x0a46, 0x0269), /* DM962OA USB to Fast Ethernet Adapter */ | |
7271 | + .driver_info = (unsigned long)&dm9601_info, | |
7272 | + }, | |
7273 | + { | |
7274 | + USB_DEVICE(0x0a46, 0x1269), /* DM9621A USB to Fast Ethernet Adapter */ | |
7275 | + .driver_info = (unsigned long)&dm9601_info, | |
7276 | + }, | |
7277 | + {}, // END | |
7278 | +}; | |
7279 | + | |
7280 | +MODULE_DEVICE_TABLE(usb, products); | |
7281 | + | |
7282 | +static struct usb_driver dm9601_driver = { | |
7283 | + .name = "dm9601", | |
7284 | + .id_table = products, | |
7285 | + .probe = usbnet_probe, | |
7286 | + .disconnect = usbnet_disconnect, | |
7287 | + .suspend = usbnet_suspend, | |
7288 | + .resume = usbnet_resume, | |
7289 | + .disable_hub_initiated_lpm = 1, | |
7290 | +}; | |
7291 | + | |
7292 | +module_usb_driver(dm9601_driver); | |
7293 | + | |
7294 | +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); | |
7295 | +MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices"); | |
7296 | +MODULE_LICENSE("GPL"); | |
7297 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/gl620a.c backports-3.18.1-1/drivers/net/usb/gl620a.c | |
7298 | --- backports-3.18.1-1.org/drivers/net/usb/gl620a.c 1970-01-01 01:00:00.000000000 +0100 | |
7299 | +++ backports-3.18.1-1/drivers/net/usb/gl620a.c 2014-12-16 18:39:45.000000000 +0100 | |
7300 | @@ -0,0 +1,242 @@ | |
7301 | +/* | |
7302 | + * GeneSys GL620USB-A based links | |
7303 | + * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw> | |
7304 | + * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz> | |
7305 | + * | |
7306 | + * This program is free software; you can redistribute it and/or modify | |
7307 | + * it under the terms of the GNU General Public License as published by | |
7308 | + * the Free Software Foundation; either version 2 of the License, or | |
7309 | + * (at your option) any later version. | |
7310 | + * | |
7311 | + * This program is distributed in the hope that it will be useful, | |
7312 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
7313 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
7314 | + * GNU General Public License for more details. | |
7315 | + * | |
7316 | + * You should have received a copy of the GNU General Public License | |
7317 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
7318 | + */ | |
7319 | + | |
7320 | +// #define DEBUG // error path messages, extra info | |
7321 | +// #define VERBOSE // more; success messages | |
7322 | + | |
7323 | +#include <linux/module.h> | |
7324 | +#include <linux/netdevice.h> | |
7325 | +#include <linux/etherdevice.h> | |
7326 | +#include <linux/ethtool.h> | |
7327 | +#include <linux/workqueue.h> | |
7328 | +#include <linux/mii.h> | |
7329 | +#include <linux/usb.h> | |
7330 | +#include <linux/usb/usbnet.h> | |
7331 | +#include <linux/gfp.h> | |
7332 | + | |
7333 | + | |
7334 | +/* | |
7335 | + * GeneSys GL620USB-A (www.genesyslogic.com.tw) | |
7336 | + * | |
7337 | + * ... should partially interop with the Win32 driver for this hardware. | |
7338 | + * The GeneSys docs imply there's some NDIS issue motivating this framing. | |
7339 | + * | |
7340 | + * Some info from GeneSys: | |
7341 | + * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk. | |
7342 | + * (Some cables, like the BAFO-100c, use the half duplex version.) | |
7343 | + * - For the full duplex model, the low bit of the version code says | |
7344 | + * which side is which ("left/right"). | |
7345 | + * - For the half duplex type, a control/interrupt handshake settles | |
7346 | + * the transfer direction. (That's disabled here, partially coded.) | |
7347 | + * A control URB would block until other side writes an interrupt. | |
7348 | + * | |
7349 | + * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw> | |
7350 | + * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>. | |
7351 | + */ | |
7352 | + | |
7353 | +// control msg write command | |
7354 | +#define GENELINK_CONNECT_WRITE 0xF0 | |
7355 | +// interrupt pipe index | |
7356 | +#define GENELINK_INTERRUPT_PIPE 0x03 | |
7357 | +// interrupt read buffer size | |
7358 | +#define INTERRUPT_BUFSIZE 0x08 | |
7359 | +// interrupt pipe interval value | |
7360 | +#define GENELINK_INTERRUPT_INTERVAL 0x10 | |
7361 | +// max transmit packet number per transmit | |
7362 | +#define GL_MAX_TRANSMIT_PACKETS 32 | |
7363 | +// max packet length | |
7364 | +#define GL_MAX_PACKET_LEN 1514 | |
7365 | +// max receive buffer size | |
7366 | +#define GL_RCV_BUF_SIZE \ | |
7367 | + (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4) | |
7368 | + | |
7369 | +struct gl_packet { | |
7370 | + __le32 packet_length; | |
7371 | + char packet_data [1]; | |
7372 | +}; | |
7373 | + | |
7374 | +struct gl_header { | |
7375 | + __le32 packet_count; | |
7376 | + struct gl_packet packets; | |
7377 | +}; | |
7378 | + | |
7379 | +static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
7380 | +{ | |
7381 | + struct gl_header *header; | |
7382 | + struct gl_packet *packet; | |
7383 | + struct sk_buff *gl_skb; | |
7384 | + u32 size; | |
7385 | + u32 count; | |
7386 | + | |
7387 | + /* This check is no longer done by usbnet */ | |
7388 | + if (skb->len < dev->net->hard_header_len) | |
7389 | + return 0; | |
7390 | + | |
7391 | + header = (struct gl_header *) skb->data; | |
7392 | + | |
7393 | + // get the packet count of the received skb | |
7394 | + count = le32_to_cpu(header->packet_count); | |
7395 | + if (count > GL_MAX_TRANSMIT_PACKETS) { | |
7396 | + netdev_dbg(dev->net, | |
7397 | + "genelink: invalid received packet count %u\n", | |
7398 | + count); | |
7399 | + return 0; | |
7400 | + } | |
7401 | + | |
7402 | + // set the current packet pointer to the first packet | |
7403 | + packet = &header->packets; | |
7404 | + | |
7405 | + // decrement the length for the packet count size 4 bytes | |
7406 | + skb_pull(skb, 4); | |
7407 | + | |
7408 | + while (count > 1) { | |
7409 | + // get the packet length | |
7410 | + size = le32_to_cpu(packet->packet_length); | |
7411 | + | |
7412 | + // this may be a broken packet | |
7413 | + if (size > GL_MAX_PACKET_LEN) { | |
7414 | + netdev_dbg(dev->net, "genelink: invalid rx length %d\n", | |
7415 | + size); | |
7416 | + return 0; | |
7417 | + } | |
7418 | + | |
7419 | + // allocate the skb for the individual packet | |
7420 | + gl_skb = alloc_skb(size, GFP_ATOMIC); | |
7421 | + if (gl_skb) { | |
7422 | + | |
7423 | + // copy the packet data to the new skb | |
7424 | + memcpy(skb_put(gl_skb, size), | |
7425 | + packet->packet_data, size); | |
7426 | + usbnet_skb_return(dev, gl_skb); | |
7427 | + } | |
7428 | + | |
7429 | + // advance to the next packet | |
7430 | + packet = (struct gl_packet *)&packet->packet_data[size]; | |
7431 | + count--; | |
7432 | + | |
7433 | + // shift the data pointer to the next gl_packet | |
7434 | + skb_pull(skb, size + 4); | |
7435 | + } | |
7436 | + | |
7437 | + // skip the packet length field 4 bytes | |
7438 | + skb_pull(skb, 4); | |
7439 | + | |
7440 | + if (skb->len > GL_MAX_PACKET_LEN) { | |
7441 | + netdev_dbg(dev->net, "genelink: invalid rx length %d\n", | |
7442 | + skb->len); | |
7443 | + return 0; | |
7444 | + } | |
7445 | + return 1; | |
7446 | +} | |
7447 | + | |
7448 | +static struct sk_buff * | |
7449 | +genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |
7450 | +{ | |
7451 | + int padlen; | |
7452 | + int length = skb->len; | |
7453 | + int headroom = skb_headroom(skb); | |
7454 | + int tailroom = skb_tailroom(skb); | |
7455 | + __le32 *packet_count; | |
7456 | + __le32 *packet_len; | |
7457 | + | |
7458 | + // FIXME: magic numbers, bleech | |
7459 | + padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; | |
7460 | + | |
7461 | + if ((!skb_cloned(skb)) | |
7462 | + && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { | |
7463 | + if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { | |
7464 | + skb->data = memmove(skb->head + (4 + 4*1), | |
7465 | + skb->data, skb->len); | |
7466 | + skb_set_tail_pointer(skb, skb->len); | |
7467 | + } | |
7468 | + } else { | |
7469 | + struct sk_buff *skb2; | |
7470 | + skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags); | |
7471 | + dev_kfree_skb_any(skb); | |
7472 | + skb = skb2; | |
7473 | + if (!skb) | |
7474 | + return NULL; | |
7475 | + } | |
7476 | + | |
7477 | + // attach the packet count to the header | |
7478 | + packet_count = (__le32 *) skb_push(skb, (4 + 4*1)); | |
7479 | + packet_len = packet_count + 1; | |
7480 | + | |
7481 | + *packet_count = cpu_to_le32(1); | |
7482 | + *packet_len = cpu_to_le32(length); | |
7483 | + | |
7484 | + // add padding byte | |
7485 | + if ((skb->len % dev->maxpacket) == 0) | |
7486 | + skb_put(skb, 1); | |
7487 | + | |
7488 | + return skb; | |
7489 | +} | |
7490 | + | |
7491 | +static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) | |
7492 | +{ | |
7493 | + dev->hard_mtu = GL_RCV_BUF_SIZE; | |
7494 | + dev->net->hard_header_len += 4; | |
7495 | + dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in); | |
7496 | + dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out); | |
7497 | + return 0; | |
7498 | +} | |
7499 | + | |
7500 | +static const struct driver_info genelink_info = { | |
7501 | + .description = "Genesys GeneLink", | |
7502 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT, | |
7503 | + .bind = genelink_bind, | |
7504 | + .rx_fixup = genelink_rx_fixup, | |
7505 | + .tx_fixup = genelink_tx_fixup, | |
7506 | + | |
7507 | + .in = 1, .out = 2, | |
7508 | + | |
7509 | +#ifdef GENELINK_ACK | |
7510 | + .check_connect =genelink_check_connect, | |
7511 | +#endif | |
7512 | +}; | |
7513 | + | |
7514 | +static const struct usb_device_id products [] = { | |
7515 | + | |
7516 | +{ | |
7517 | + USB_DEVICE(0x05e3, 0x0502), // GL620USB-A | |
7518 | + .driver_info = (unsigned long) &genelink_info, | |
7519 | +}, | |
7520 | + /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB | |
7521 | + * that's half duplex, not currently supported | |
7522 | + */ | |
7523 | + { }, // END | |
7524 | +}; | |
7525 | +MODULE_DEVICE_TABLE(usb, products); | |
7526 | + | |
7527 | +static struct usb_driver gl620a_driver = { | |
7528 | + .name = "gl620a", | |
7529 | + .id_table = products, | |
7530 | + .probe = usbnet_probe, | |
7531 | + .disconnect = usbnet_disconnect, | |
7532 | + .suspend = usbnet_suspend, | |
7533 | + .resume = usbnet_resume, | |
7534 | + .disable_hub_initiated_lpm = 1, | |
7535 | +}; | |
7536 | + | |
7537 | +module_usb_driver(gl620a_driver); | |
7538 | + | |
7539 | +MODULE_AUTHOR("Jiun-Jie Huang"); | |
7540 | +MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables"); | |
7541 | +MODULE_LICENSE("GPL"); | |
7542 | + | |
7543 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/hso.c backports-3.18.1-1/drivers/net/usb/hso.c | |
7544 | --- backports-3.18.1-1.org/drivers/net/usb/hso.c 1970-01-01 01:00:00.000000000 +0100 | |
7545 | +++ backports-3.18.1-1/drivers/net/usb/hso.c 2015-01-03 13:42:25.000000000 +0100 | |
7546 | @@ -0,0 +1,3326 @@ | |
7547 | +/****************************************************************************** | |
7548 | + * | |
7549 | + * Driver for Option High Speed Mobile Devices. | |
7550 | + * | |
7551 | + * Copyright (C) 2008 Option International | |
7552 | + * Filip Aben <f.aben@option.com> | |
7553 | + * Denis Joseph Barrow <d.barow@option.com> | |
7554 | + * Jan Dumon <j.dumon@option.com> | |
7555 | + * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) | |
7556 | + * <ajb@spheresystems.co.uk> | |
7557 | + * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> | |
7558 | + * Copyright (C) 2008 Novell, Inc. | |
7559 | + * | |
7560 | + * This program is free software; you can redistribute it and/or modify | |
7561 | + * it under the terms of the GNU General Public License version 2 as | |
7562 | + * published by the Free Software Foundation. | |
7563 | + * | |
7564 | + * This program is distributed in the hope that it will be useful, | |
7565 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
7566 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
7567 | + * GNU General Public License for more details. | |
7568 | + * | |
7569 | + * You should have received a copy of the GNU General Public License | |
7570 | + * along with this program; if not, write to the Free Software | |
7571 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |
7572 | + * USA | |
7573 | + * | |
7574 | + * | |
7575 | + *****************************************************************************/ | |
7576 | + | |
7577 | +/****************************************************************************** | |
7578 | + * | |
7579 | + * Description of the device: | |
7580 | + * | |
7581 | + * Interface 0: Contains the IP network interface on the bulk end points. | |
7582 | + * The multiplexed serial ports are using the interrupt and | |
7583 | + * control endpoints. | |
7584 | + * Interrupt contains a bitmap telling which multiplexed | |
7585 | + * serialport needs servicing. | |
7586 | + * | |
7587 | + * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the | |
7588 | + * port is opened, as this have a huge impact on the network port | |
7589 | + * throughput. | |
7590 | + * | |
7591 | + * Interface 2: Standard modem interface - circuit switched interface, this | |
7592 | + * can be used to make a standard ppp connection however it | |
7593 | + * should not be used in conjunction with the IP network interface | |
7594 | + * enabled for USB performance reasons i.e. if using this set | |
7595 | + * ideally disable_net=1. | |
7596 | + * | |
7597 | + *****************************************************************************/ | |
7598 | + | |
7599 | +#include <linux/sched.h> | |
7600 | +#include <linux/slab.h> | |
7601 | +#include <linux/init.h> | |
7602 | +#include <linux/delay.h> | |
7603 | +#include <linux/netdevice.h> | |
7604 | +#include <linux/module.h> | |
7605 | +#include <linux/ethtool.h> | |
7606 | +#include <linux/usb.h> | |
7607 | +#include <linux/timer.h> | |
7608 | +#include <linux/tty.h> | |
7609 | +#include <linux/tty_driver.h> | |
7610 | +#include <linux/tty_flip.h> | |
7611 | +#include <linux/kmod.h> | |
7612 | +#include <linux/rfkill.h> | |
7613 | +#include <linux/ip.h> | |
7614 | +#include <linux/uaccess.h> | |
7615 | +#include <linux/usb/cdc.h> | |
7616 | +#include <net/arp.h> | |
7617 | +#include <asm/byteorder.h> | |
7618 | +#include <linux/serial_core.h> | |
7619 | +#include <linux/serial.h> | |
7620 | +#include <asm/local.h> | |
7621 | + | |
7622 | +#define MOD_AUTHOR "Option Wireless" | |
7623 | +#define MOD_DESCRIPTION "USB High Speed Option driver" | |
7624 | +#define MOD_LICENSE "GPL" | |
7625 | + | |
7626 | +#define HSO_MAX_NET_DEVICES 10 | |
7627 | +#define HSO__MAX_MTU 2048 | |
7628 | +#define DEFAULT_MTU 1500 | |
7629 | +#define DEFAULT_MRU 1500 | |
7630 | + | |
7631 | +#define CTRL_URB_RX_SIZE 1024 | |
7632 | +#define CTRL_URB_TX_SIZE 64 | |
7633 | + | |
7634 | +#define BULK_URB_RX_SIZE 4096 | |
7635 | +#define BULK_URB_TX_SIZE 8192 | |
7636 | + | |
7637 | +#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU | |
7638 | +#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU | |
7639 | +#define MUX_BULK_RX_BUF_COUNT 4 | |
7640 | +#define USB_TYPE_OPTION_VENDOR 0x20 | |
7641 | + | |
7642 | +/* These definitions are used with the struct hso_net flags element */ | |
7643 | +/* - use *_bit operations on it. (bit indices not values.) */ | |
7644 | +#define HSO_NET_RUNNING 0 | |
7645 | + | |
7646 | +#define HSO_NET_TX_TIMEOUT (HZ*10) | |
7647 | + | |
7648 | +#define HSO_SERIAL_MAGIC 0x48534f31 | |
7649 | + | |
7650 | +/* Number of ttys to handle */ | |
7651 | +#define HSO_SERIAL_TTY_MINORS 256 | |
7652 | + | |
7653 | +#define MAX_RX_URBS 2 | |
7654 | + | |
7655 | +/*****************************************************************************/ | |
7656 | +/* Debugging functions */ | |
7657 | +/*****************************************************************************/ | |
7658 | +#define D__(lvl_, fmt, arg...) \ | |
7659 | + do { \ | |
7660 | + printk(lvl_ "[%d:%s]: " fmt "\n", \ | |
7661 | + __LINE__, __func__, ## arg); \ | |
7662 | + } while (0) | |
7663 | + | |
7664 | +#define D_(lvl, args...) \ | |
7665 | + do { \ | |
7666 | + if (lvl & debug) \ | |
7667 | + D__(KERN_INFO, args); \ | |
7668 | + } while (0) | |
7669 | + | |
7670 | +#define D1(args...) D_(0x01, ##args) | |
7671 | +#define D2(args...) D_(0x02, ##args) | |
7672 | +#define D3(args...) D_(0x04, ##args) | |
7673 | +#define D4(args...) D_(0x08, ##args) | |
7674 | +#define D5(args...) D_(0x10, ##args) | |
7675 | + | |
7676 | +/*****************************************************************************/ | |
7677 | +/* Enumerators */ | |
7678 | +/*****************************************************************************/ | |
7679 | +enum pkt_parse_state { | |
7680 | + WAIT_IP, | |
7681 | + WAIT_DATA, | |
7682 | + WAIT_SYNC | |
7683 | +}; | |
7684 | + | |
7685 | +/*****************************************************************************/ | |
7686 | +/* Structs */ | |
7687 | +/*****************************************************************************/ | |
7688 | + | |
7689 | +struct hso_shared_int { | |
7690 | + struct usb_endpoint_descriptor *intr_endp; | |
7691 | + void *shared_intr_buf; | |
7692 | + struct urb *shared_intr_urb; | |
7693 | + struct usb_device *usb; | |
7694 | + int use_count; | |
7695 | + int ref_count; | |
7696 | + struct mutex shared_int_lock; | |
7697 | +}; | |
7698 | + | |
7699 | +struct hso_net { | |
7700 | + struct hso_device *parent; | |
7701 | + struct net_device *net; | |
7702 | + struct rfkill *rfkill; | |
7703 | + | |
7704 | + struct usb_endpoint_descriptor *in_endp; | |
7705 | + struct usb_endpoint_descriptor *out_endp; | |
7706 | + | |
7707 | + struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT]; | |
7708 | + struct urb *mux_bulk_tx_urb; | |
7709 | + void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT]; | |
7710 | + void *mux_bulk_tx_buf; | |
7711 | + | |
7712 | + struct sk_buff *skb_rx_buf; | |
7713 | + struct sk_buff *skb_tx_buf; | |
7714 | + | |
7715 | + enum pkt_parse_state rx_parse_state; | |
7716 | + spinlock_t net_lock; | |
7717 | + | |
7718 | + unsigned short rx_buf_size; | |
7719 | + unsigned short rx_buf_missing; | |
7720 | + struct iphdr rx_ip_hdr; | |
7721 | + | |
7722 | + unsigned long flags; | |
7723 | +}; | |
7724 | + | |
7725 | +enum rx_ctrl_state{ | |
7726 | + RX_IDLE, | |
7727 | + RX_SENT, | |
7728 | + RX_PENDING | |
7729 | +}; | |
7730 | + | |
7731 | +#define BM_REQUEST_TYPE (0xa1) | |
7732 | +#define B_NOTIFICATION (0x20) | |
7733 | +#define W_VALUE (0x0) | |
7734 | +#define W_LENGTH (0x2) | |
7735 | + | |
7736 | +#define B_OVERRUN (0x1<<6) | |
7737 | +#define B_PARITY (0x1<<5) | |
7738 | +#define B_FRAMING (0x1<<4) | |
7739 | +#define B_RING_SIGNAL (0x1<<3) | |
7740 | +#define B_BREAK (0x1<<2) | |
7741 | +#define B_TX_CARRIER (0x1<<1) | |
7742 | +#define B_RX_CARRIER (0x1<<0) | |
7743 | + | |
7744 | +struct hso_serial_state_notification { | |
7745 | + u8 bmRequestType; | |
7746 | + u8 bNotification; | |
7747 | + u16 wValue; | |
7748 | + u16 wIndex; | |
7749 | + u16 wLength; | |
7750 | + u16 UART_state_bitmap; | |
7751 | +} __packed; | |
7752 | + | |
7753 | +struct hso_tiocmget { | |
7754 | + struct mutex mutex; | |
7755 | + wait_queue_head_t waitq; | |
7756 | + int intr_completed; | |
7757 | + struct usb_endpoint_descriptor *endp; | |
7758 | + struct urb *urb; | |
7759 | + struct hso_serial_state_notification serial_state_notification; | |
7760 | + u16 prev_UART_state_bitmap; | |
7761 | + struct uart_icount icount; | |
7762 | +}; | |
7763 | + | |
7764 | + | |
7765 | +struct hso_serial { | |
7766 | + struct hso_device *parent; | |
7767 | + int magic; | |
7768 | + u8 minor; | |
7769 | + | |
7770 | + struct hso_shared_int *shared_int; | |
7771 | + | |
7772 | + /* rx/tx urb could be either a bulk urb or a control urb depending | |
7773 | + on which serial port it is used on. */ | |
7774 | + struct urb *rx_urb[MAX_RX_URBS]; | |
7775 | + u8 num_rx_urbs; | |
7776 | + u8 *rx_data[MAX_RX_URBS]; | |
7777 | + u16 rx_data_length; /* should contain allocated length */ | |
7778 | + | |
7779 | + struct urb *tx_urb; | |
7780 | + u8 *tx_data; | |
7781 | + u8 *tx_buffer; | |
7782 | + u16 tx_data_length; /* should contain allocated length */ | |
7783 | + u16 tx_data_count; | |
7784 | + u16 tx_buffer_count; | |
7785 | + struct usb_ctrlrequest ctrl_req_tx; | |
7786 | + struct usb_ctrlrequest ctrl_req_rx; | |
7787 | + | |
7788 | + struct usb_endpoint_descriptor *in_endp; | |
7789 | + struct usb_endpoint_descriptor *out_endp; | |
7790 | + | |
7791 | + enum rx_ctrl_state rx_state; | |
7792 | + u8 rts_state; | |
7793 | + u8 dtr_state; | |
7794 | + unsigned tx_urb_used:1; | |
7795 | + | |
7796 | + struct tty_port port; | |
7797 | + /* from usb_serial_port */ | |
7798 | + spinlock_t serial_lock; | |
7799 | + | |
7800 | + int (*write_data) (struct hso_serial *serial); | |
7801 | + struct hso_tiocmget *tiocmget; | |
7802 | + /* Hacks required to get flow control | |
7803 | + * working on the serial receive buffers | |
7804 | + * so as not to drop characters on the floor. | |
7805 | + */ | |
7806 | + int curr_rx_urb_idx; | |
7807 | + u8 rx_urb_filled[MAX_RX_URBS]; | |
7808 | + struct tasklet_struct unthrottle_tasklet; | |
7809 | +}; | |
7810 | + | |
7811 | +struct hso_device { | |
7812 | + union { | |
7813 | + struct hso_serial *dev_serial; | |
7814 | + struct hso_net *dev_net; | |
7815 | + } port_data; | |
7816 | + | |
7817 | + u32 port_spec; | |
7818 | + | |
7819 | + u8 is_active; | |
7820 | + u8 usb_gone; | |
7821 | + struct work_struct async_get_intf; | |
7822 | + struct work_struct async_put_intf; | |
7823 | + struct work_struct reset_device; | |
7824 | + | |
7825 | + struct usb_device *usb; | |
7826 | + struct usb_interface *interface; | |
7827 | + | |
7828 | + struct device *dev; | |
7829 | + struct kref ref; | |
7830 | + struct mutex mutex; | |
7831 | +}; | |
7832 | + | |
7833 | +/* Type of interface */ | |
7834 | +#define HSO_INTF_MASK 0xFF00 | |
7835 | +#define HSO_INTF_MUX 0x0100 | |
7836 | +#define HSO_INTF_BULK 0x0200 | |
7837 | + | |
7838 | +/* Type of port */ | |
7839 | +#define HSO_PORT_MASK 0xFF | |
7840 | +#define HSO_PORT_NO_PORT 0x0 | |
7841 | +#define HSO_PORT_CONTROL 0x1 | |
7842 | +#define HSO_PORT_APP 0x2 | |
7843 | +#define HSO_PORT_GPS 0x3 | |
7844 | +#define HSO_PORT_PCSC 0x4 | |
7845 | +#define HSO_PORT_APP2 0x5 | |
7846 | +#define HSO_PORT_GPS_CONTROL 0x6 | |
7847 | +#define HSO_PORT_MSD 0x7 | |
7848 | +#define HSO_PORT_VOICE 0x8 | |
7849 | +#define HSO_PORT_DIAG2 0x9 | |
7850 | +#define HSO_PORT_DIAG 0x10 | |
7851 | +#define HSO_PORT_MODEM 0x11 | |
7852 | +#define HSO_PORT_NETWORK 0x12 | |
7853 | + | |
7854 | +/* Additional device info */ | |
7855 | +#define HSO_INFO_MASK 0xFF000000 | |
7856 | +#define HSO_INFO_CRC_BUG 0x01000000 | |
7857 | + | |
7858 | +/*****************************************************************************/ | |
7859 | +/* Prototypes */ | |
7860 | +/*****************************************************************************/ | |
7861 | +/* Serial driver functions */ | |
7862 | +static int hso_serial_tiocmset(struct tty_struct *tty, | |
7863 | + unsigned int set, unsigned int clear); | |
7864 | +static void ctrl_callback(struct urb *urb); | |
7865 | +static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); | |
7866 | +static void hso_kick_transmit(struct hso_serial *serial); | |
7867 | +/* Helper functions */ | |
7868 | +static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, | |
7869 | + struct usb_device *usb, gfp_t gfp); | |
7870 | +static void handle_usb_error(int status, const char *function, | |
7871 | + struct hso_device *hso_dev); | |
7872 | +static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, | |
7873 | + int type, int dir); | |
7874 | +static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports); | |
7875 | +static void hso_free_interface(struct usb_interface *intf); | |
7876 | +static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags); | |
7877 | +static int hso_stop_serial_device(struct hso_device *hso_dev); | |
7878 | +static int hso_start_net_device(struct hso_device *hso_dev); | |
7879 | +static void hso_free_shared_int(struct hso_shared_int *shared_int); | |
7880 | +static int hso_stop_net_device(struct hso_device *hso_dev); | |
7881 | +static void hso_serial_ref_free(struct kref *ref); | |
7882 | +static void hso_std_serial_read_bulk_callback(struct urb *urb); | |
7883 | +static int hso_mux_serial_read(struct hso_serial *serial); | |
7884 | +static void async_get_intf(struct work_struct *data); | |
7885 | +static void async_put_intf(struct work_struct *data); | |
7886 | +static int hso_put_activity(struct hso_device *hso_dev); | |
7887 | +static int hso_get_activity(struct hso_device *hso_dev); | |
7888 | +static void tiocmget_intr_callback(struct urb *urb); | |
7889 | +static void reset_device(struct work_struct *data); | |
7890 | +/*****************************************************************************/ | |
7891 | +/* Helping functions */ | |
7892 | +/*****************************************************************************/ | |
7893 | + | |
7894 | +/* #define DEBUG */ | |
7895 | + | |
7896 | +static inline struct hso_net *dev2net(struct hso_device *hso_dev) | |
7897 | +{ | |
7898 | + return hso_dev->port_data.dev_net; | |
7899 | +} | |
7900 | + | |
7901 | +static inline struct hso_serial *dev2ser(struct hso_device *hso_dev) | |
7902 | +{ | |
7903 | + return hso_dev->port_data.dev_serial; | |
7904 | +} | |
7905 | + | |
7906 | +/* Debugging functions */ | |
7907 | +#ifdef DEBUG | |
7908 | +static void dbg_dump(int line_count, const char *func_name, unsigned char *buf, | |
7909 | + unsigned int len) | |
7910 | +{ | |
7911 | + static char name[255]; | |
7912 | + | |
7913 | + sprintf(name, "hso[%d:%s]", line_count, func_name); | |
7914 | + print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len); | |
7915 | +} | |
7916 | + | |
7917 | +#define DUMP(buf_, len_) \ | |
7918 | + dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_) | |
7919 | + | |
7920 | +#define DUMP1(buf_, len_) \ | |
7921 | + do { \ | |
7922 | + if (0x01 & debug) \ | |
7923 | + DUMP(buf_, len_); \ | |
7924 | + } while (0) | |
7925 | +#else | |
7926 | +#define DUMP(buf_, len_) | |
7927 | +#define DUMP1(buf_, len_) | |
7928 | +#endif | |
7929 | + | |
7930 | +/* module parameters */ | |
7931 | +static int debug; | |
7932 | +static int tty_major; | |
7933 | +static int disable_net; | |
7934 | + | |
7935 | +/* driver info */ | |
7936 | +static const char driver_name[] = "hso"; | |
7937 | +static const char tty_filename[] = "ttyHS"; | |
7938 | +static const char *version = __FILE__ ": " MOD_AUTHOR; | |
7939 | +/* the usb driver itself (registered in hso_init) */ | |
7940 | +static struct usb_driver hso_driver; | |
7941 | +/* serial structures */ | |
7942 | +static struct tty_driver *tty_drv; | |
7943 | +static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; | |
7944 | +static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; | |
7945 | +static spinlock_t serial_table_lock; | |
7946 | + | |
7947 | +static const s32 default_port_spec[] = { | |
7948 | + HSO_INTF_MUX | HSO_PORT_NETWORK, | |
7949 | + HSO_INTF_BULK | HSO_PORT_DIAG, | |
7950 | + HSO_INTF_BULK | HSO_PORT_MODEM, | |
7951 | + 0 | |
7952 | +}; | |
7953 | + | |
7954 | +static const s32 icon321_port_spec[] = { | |
7955 | + HSO_INTF_MUX | HSO_PORT_NETWORK, | |
7956 | + HSO_INTF_BULK | HSO_PORT_DIAG2, | |
7957 | + HSO_INTF_BULK | HSO_PORT_MODEM, | |
7958 | + HSO_INTF_BULK | HSO_PORT_DIAG, | |
7959 | + 0 | |
7960 | +}; | |
7961 | + | |
7962 | +#define default_port_device(vendor, product) \ | |
7963 | + USB_DEVICE(vendor, product), \ | |
7964 | + .driver_info = (kernel_ulong_t)default_port_spec | |
7965 | + | |
7966 | +#define icon321_port_device(vendor, product) \ | |
7967 | + USB_DEVICE(vendor, product), \ | |
7968 | + .driver_info = (kernel_ulong_t)icon321_port_spec | |
7969 | + | |
7970 | +/* list of devices we support */ | |
7971 | +static const struct usb_device_id hso_ids[] = { | |
7972 | + {default_port_device(0x0af0, 0x6711)}, | |
7973 | + {default_port_device(0x0af0, 0x6731)}, | |
7974 | + {default_port_device(0x0af0, 0x6751)}, | |
7975 | + {default_port_device(0x0af0, 0x6771)}, | |
7976 | + {default_port_device(0x0af0, 0x6791)}, | |
7977 | + {default_port_device(0x0af0, 0x6811)}, | |
7978 | + {default_port_device(0x0af0, 0x6911)}, | |
7979 | + {default_port_device(0x0af0, 0x6951)}, | |
7980 | + {default_port_device(0x0af0, 0x6971)}, | |
7981 | + {default_port_device(0x0af0, 0x7011)}, | |
7982 | + {default_port_device(0x0af0, 0x7031)}, | |
7983 | + {default_port_device(0x0af0, 0x7051)}, | |
7984 | + {default_port_device(0x0af0, 0x7071)}, | |
7985 | + {default_port_device(0x0af0, 0x7111)}, | |
7986 | + {default_port_device(0x0af0, 0x7211)}, | |
7987 | + {default_port_device(0x0af0, 0x7251)}, | |
7988 | + {default_port_device(0x0af0, 0x7271)}, | |
7989 | + {default_port_device(0x0af0, 0x7311)}, | |
7990 | + {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ | |
7991 | + {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ | |
7992 | + {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ | |
7993 | + {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */ | |
7994 | + {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ | |
7995 | + {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ | |
7996 | + {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */ | |
7997 | + {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ | |
7998 | + {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ | |
7999 | + {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ | |
8000 | + {USB_DEVICE(0x0af0, 0x7701)}, | |
8001 | + {USB_DEVICE(0x0af0, 0x7706)}, | |
8002 | + {USB_DEVICE(0x0af0, 0x7801)}, | |
8003 | + {USB_DEVICE(0x0af0, 0x7901)}, | |
8004 | + {USB_DEVICE(0x0af0, 0x7A01)}, | |
8005 | + {USB_DEVICE(0x0af0, 0x7A05)}, | |
8006 | + {USB_DEVICE(0x0af0, 0x8200)}, | |
8007 | + {USB_DEVICE(0x0af0, 0x8201)}, | |
8008 | + {USB_DEVICE(0x0af0, 0x8300)}, | |
8009 | + {USB_DEVICE(0x0af0, 0x8302)}, | |
8010 | + {USB_DEVICE(0x0af0, 0x8304)}, | |
8011 | + {USB_DEVICE(0x0af0, 0x8400)}, | |
8012 | + {USB_DEVICE(0x0af0, 0x8600)}, | |
8013 | + {USB_DEVICE(0x0af0, 0x8800)}, | |
8014 | + {USB_DEVICE(0x0af0, 0x8900)}, | |
8015 | + {USB_DEVICE(0x0af0, 0x9000)}, | |
8016 | + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ | |
8017 | + {USB_DEVICE(0x0af0, 0xd035)}, | |
8018 | + {USB_DEVICE(0x0af0, 0xd055)}, | |
8019 | + {USB_DEVICE(0x0af0, 0xd155)}, | |
8020 | + {USB_DEVICE(0x0af0, 0xd255)}, | |
8021 | + {USB_DEVICE(0x0af0, 0xd057)}, | |
8022 | + {USB_DEVICE(0x0af0, 0xd157)}, | |
8023 | + {USB_DEVICE(0x0af0, 0xd257)}, | |
8024 | + {USB_DEVICE(0x0af0, 0xd357)}, | |
8025 | + {USB_DEVICE(0x0af0, 0xd058)}, | |
8026 | + {USB_DEVICE(0x0af0, 0xc100)}, | |
8027 | + {} | |
8028 | +}; | |
8029 | +MODULE_DEVICE_TABLE(usb, hso_ids); | |
8030 | + | |
8031 | +/* Sysfs attribute */ | |
8032 | +static ssize_t hso_sysfs_show_porttype(struct device *dev, | |
8033 | + struct device_attribute *attr, | |
8034 | + char *buf) | |
8035 | +{ | |
8036 | + struct hso_device *hso_dev = dev_get_drvdata(dev); | |
8037 | + char *port_name; | |
8038 | + | |
8039 | + if (!hso_dev) | |
8040 | + return 0; | |
8041 | + | |
8042 | + switch (hso_dev->port_spec & HSO_PORT_MASK) { | |
8043 | + case HSO_PORT_CONTROL: | |
8044 | + port_name = "Control"; | |
8045 | + break; | |
8046 | + case HSO_PORT_APP: | |
8047 | + port_name = "Application"; | |
8048 | + break; | |
8049 | + case HSO_PORT_APP2: | |
8050 | + port_name = "Application2"; | |
8051 | + break; | |
8052 | + case HSO_PORT_GPS: | |
8053 | + port_name = "GPS"; | |
8054 | + break; | |
8055 | + case HSO_PORT_GPS_CONTROL: | |
8056 | + port_name = "GPS Control"; | |
8057 | + break; | |
8058 | + case HSO_PORT_PCSC: | |
8059 | + port_name = "PCSC"; | |
8060 | + break; | |
8061 | + case HSO_PORT_DIAG: | |
8062 | + port_name = "Diagnostic"; | |
8063 | + break; | |
8064 | + case HSO_PORT_DIAG2: | |
8065 | + port_name = "Diagnostic2"; | |
8066 | + break; | |
8067 | + case HSO_PORT_MODEM: | |
8068 | + port_name = "Modem"; | |
8069 | + break; | |
8070 | + case HSO_PORT_NETWORK: | |
8071 | + port_name = "Network"; | |
8072 | + break; | |
8073 | + default: | |
8074 | + port_name = "Unknown"; | |
8075 | + break; | |
8076 | + } | |
8077 | + | |
8078 | + return sprintf(buf, "%s\n", port_name); | |
8079 | +} | |
8080 | +static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); | |
8081 | + | |
8082 | +static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) | |
8083 | +{ | |
8084 | + int idx; | |
8085 | + | |
8086 | + for (idx = 0; idx < serial->num_rx_urbs; idx++) | |
8087 | + if (serial->rx_urb[idx] == urb) | |
8088 | + return idx; | |
8089 | + dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); | |
8090 | + return -1; | |
8091 | +} | |
8092 | + | |
8093 | +/* converts mux value to a port spec value */ | |
8094 | +static u32 hso_mux_to_port(int mux) | |
8095 | +{ | |
8096 | + u32 result; | |
8097 | + | |
8098 | + switch (mux) { | |
8099 | + case 0x1: | |
8100 | + result = HSO_PORT_CONTROL; | |
8101 | + break; | |
8102 | + case 0x2: | |
8103 | + result = HSO_PORT_APP; | |
8104 | + break; | |
8105 | + case 0x4: | |
8106 | + result = HSO_PORT_PCSC; | |
8107 | + break; | |
8108 | + case 0x8: | |
8109 | + result = HSO_PORT_GPS; | |
8110 | + break; | |
8111 | + case 0x10: | |
8112 | + result = HSO_PORT_APP2; | |
8113 | + break; | |
8114 | + default: | |
8115 | + result = HSO_PORT_NO_PORT; | |
8116 | + } | |
8117 | + return result; | |
8118 | +} | |
8119 | + | |
8120 | +/* converts port spec value to a mux value */ | |
8121 | +static u32 hso_port_to_mux(int port) | |
8122 | +{ | |
8123 | + u32 result; | |
8124 | + | |
8125 | + switch (port & HSO_PORT_MASK) { | |
8126 | + case HSO_PORT_CONTROL: | |
8127 | + result = 0x0; | |
8128 | + break; | |
8129 | + case HSO_PORT_APP: | |
8130 | + result = 0x1; | |
8131 | + break; | |
8132 | + case HSO_PORT_PCSC: | |
8133 | + result = 0x2; | |
8134 | + break; | |
8135 | + case HSO_PORT_GPS: | |
8136 | + result = 0x3; | |
8137 | + break; | |
8138 | + case HSO_PORT_APP2: | |
8139 | + result = 0x4; | |
8140 | + break; | |
8141 | + default: | |
8142 | + result = 0x0; | |
8143 | + } | |
8144 | + return result; | |
8145 | +} | |
8146 | + | |
8147 | +static struct hso_serial *get_serial_by_shared_int_and_type( | |
8148 | + struct hso_shared_int *shared_int, | |
8149 | + int mux) | |
8150 | +{ | |
8151 | + int i, port; | |
8152 | + | |
8153 | + port = hso_mux_to_port(mux); | |
8154 | + | |
8155 | + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | |
8156 | + if (serial_table[i] && | |
8157 | + (dev2ser(serial_table[i])->shared_int == shared_int) && | |
8158 | + ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { | |
8159 | + return dev2ser(serial_table[i]); | |
8160 | + } | |
8161 | + } | |
8162 | + | |
8163 | + return NULL; | |
8164 | +} | |
8165 | + | |
8166 | +static struct hso_serial *get_serial_by_index(unsigned index) | |
8167 | +{ | |
8168 | + struct hso_serial *serial = NULL; | |
8169 | + unsigned long flags; | |
8170 | + | |
8171 | + spin_lock_irqsave(&serial_table_lock, flags); | |
8172 | + if (serial_table[index]) | |
8173 | + serial = dev2ser(serial_table[index]); | |
8174 | + spin_unlock_irqrestore(&serial_table_lock, flags); | |
8175 | + | |
8176 | + return serial; | |
8177 | +} | |
8178 | + | |
8179 | +static int get_free_serial_index(void) | |
8180 | +{ | |
8181 | + int index; | |
8182 | + unsigned long flags; | |
8183 | + | |
8184 | + spin_lock_irqsave(&serial_table_lock, flags); | |
8185 | + for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { | |
8186 | + if (serial_table[index] == NULL) { | |
8187 | + spin_unlock_irqrestore(&serial_table_lock, flags); | |
8188 | + return index; | |
8189 | + } | |
8190 | + } | |
8191 | + spin_unlock_irqrestore(&serial_table_lock, flags); | |
8192 | + | |
8193 | + printk(KERN_ERR "%s: no free serial devices in table\n", __func__); | |
8194 | + return -1; | |
8195 | +} | |
8196 | + | |
8197 | +static void set_serial_by_index(unsigned index, struct hso_serial *serial) | |
8198 | +{ | |
8199 | + unsigned long flags; | |
8200 | + | |
8201 | + spin_lock_irqsave(&serial_table_lock, flags); | |
8202 | + if (serial) | |
8203 | + serial_table[index] = serial->parent; | |
8204 | + else | |
8205 | + serial_table[index] = NULL; | |
8206 | + spin_unlock_irqrestore(&serial_table_lock, flags); | |
8207 | +} | |
8208 | + | |
8209 | +static void handle_usb_error(int status, const char *function, | |
8210 | + struct hso_device *hso_dev) | |
8211 | +{ | |
8212 | + char *explanation; | |
8213 | + | |
8214 | + switch (status) { | |
8215 | + case -ENODEV: | |
8216 | + explanation = "no device"; | |
8217 | + break; | |
8218 | + case -ENOENT: | |
8219 | + explanation = "endpoint not enabled"; | |
8220 | + break; | |
8221 | + case -EPIPE: | |
8222 | + explanation = "endpoint stalled"; | |
8223 | + break; | |
8224 | + case -ENOSPC: | |
8225 | + explanation = "not enough bandwidth"; | |
8226 | + break; | |
8227 | + case -ESHUTDOWN: | |
8228 | + explanation = "device disabled"; | |
8229 | + break; | |
8230 | + case -EHOSTUNREACH: | |
8231 | + explanation = "device suspended"; | |
8232 | + break; | |
8233 | + case -EINVAL: | |
8234 | + case -EAGAIN: | |
8235 | + case -EFBIG: | |
8236 | + case -EMSGSIZE: | |
8237 | + explanation = "internal error"; | |
8238 | + break; | |
8239 | + case -EILSEQ: | |
8240 | + case -EPROTO: | |
8241 | + case -ETIME: | |
8242 | + case -ETIMEDOUT: | |
8243 | + explanation = "protocol error"; | |
8244 | + if (hso_dev) | |
8245 | + schedule_work(&hso_dev->reset_device); | |
8246 | + break; | |
8247 | + default: | |
8248 | + explanation = "unknown status"; | |
8249 | + break; | |
8250 | + } | |
8251 | + | |
8252 | + /* log a meaningful explanation of an USB status */ | |
8253 | + D1("%s: received USB status - %s (%d)", function, explanation, status); | |
8254 | +} | |
8255 | + | |
8256 | +/* Network interface functions */ | |
8257 | + | |
8258 | +/* called when net interface is brought up by ifconfig */ | |
8259 | +static int hso_net_open(struct net_device *net) | |
8260 | +{ | |
8261 | + struct hso_net *odev = netdev_priv(net); | |
8262 | + unsigned long flags = 0; | |
8263 | + | |
8264 | + if (!odev) { | |
8265 | + dev_err(&net->dev, "No net device !\n"); | |
8266 | + return -ENODEV; | |
8267 | + } | |
8268 | + | |
8269 | + odev->skb_tx_buf = NULL; | |
8270 | + | |
8271 | + /* setup environment */ | |
8272 | + spin_lock_irqsave(&odev->net_lock, flags); | |
8273 | + odev->rx_parse_state = WAIT_IP; | |
8274 | + odev->rx_buf_size = 0; | |
8275 | + odev->rx_buf_missing = sizeof(struct iphdr); | |
8276 | + spin_unlock_irqrestore(&odev->net_lock, flags); | |
8277 | + | |
8278 | + /* We are up and running. */ | |
8279 | + set_bit(HSO_NET_RUNNING, &odev->flags); | |
8280 | + hso_start_net_device(odev->parent); | |
8281 | + | |
8282 | + /* Tell the kernel we are ready to start receiving from it */ | |
8283 | + netif_start_queue(net); | |
8284 | + | |
8285 | + return 0; | |
8286 | +} | |
8287 | + | |
8288 | +/* called when interface is brought down by ifconfig */ | |
8289 | +static int hso_net_close(struct net_device *net) | |
8290 | +{ | |
8291 | + struct hso_net *odev = netdev_priv(net); | |
8292 | + | |
8293 | + /* we don't need the queue anymore */ | |
8294 | + netif_stop_queue(net); | |
8295 | + /* no longer running */ | |
8296 | + clear_bit(HSO_NET_RUNNING, &odev->flags); | |
8297 | + | |
8298 | + hso_stop_net_device(odev->parent); | |
8299 | + | |
8300 | + /* done */ | |
8301 | + return 0; | |
8302 | +} | |
8303 | + | |
8304 | +/* USB tells is xmit done, we should start the netqueue again */ | |
8305 | +static void write_bulk_callback(struct urb *urb) | |
8306 | +{ | |
8307 | + struct hso_net *odev = urb->context; | |
8308 | + int status = urb->status; | |
8309 | + | |
8310 | + /* Sanity check */ | |
8311 | + if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { | |
8312 | + dev_err(&urb->dev->dev, "%s: device not running\n", __func__); | |
8313 | + return; | |
8314 | + } | |
8315 | + | |
8316 | + /* Do we still have a valid kernel network device? */ | |
8317 | + if (!netif_device_present(odev->net)) { | |
8318 | + dev_err(&urb->dev->dev, "%s: net device not present\n", | |
8319 | + __func__); | |
8320 | + return; | |
8321 | + } | |
8322 | + | |
8323 | + /* log status, but don't act on it, we don't need to resubmit anything | |
8324 | + * anyhow */ | |
8325 | + if (status) | |
8326 | + handle_usb_error(status, __func__, odev->parent); | |
8327 | + | |
8328 | + hso_put_activity(odev->parent); | |
8329 | + | |
8330 | + /* Tell the network interface we are ready for another frame */ | |
8331 | + netif_wake_queue(odev->net); | |
8332 | +} | |
8333 | + | |
8334 | +/* called by kernel when we need to transmit a packet */ | |
8335 | +static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, | |
8336 | + struct net_device *net) | |
8337 | +{ | |
8338 | + struct hso_net *odev = netdev_priv(net); | |
8339 | + int result; | |
8340 | + | |
8341 | + /* Tell the kernel, "No more frames 'til we are done with this one." */ | |
8342 | + netif_stop_queue(net); | |
8343 | + if (hso_get_activity(odev->parent) == -EAGAIN) { | |
8344 | + odev->skb_tx_buf = skb; | |
8345 | + return NETDEV_TX_OK; | |
8346 | + } | |
8347 | + | |
8348 | + /* log if asked */ | |
8349 | + DUMP1(skb->data, skb->len); | |
8350 | + /* Copy it from kernel memory to OUR memory */ | |
8351 | + memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); | |
8352 | + D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); | |
8353 | + | |
8354 | + /* Fill in the URB for shipping it out. */ | |
8355 | + usb_fill_bulk_urb(odev->mux_bulk_tx_urb, | |
8356 | + odev->parent->usb, | |
8357 | + usb_sndbulkpipe(odev->parent->usb, | |
8358 | + odev->out_endp-> | |
8359 | + bEndpointAddress & 0x7F), | |
8360 | + odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, | |
8361 | + odev); | |
8362 | + | |
8363 | + /* Deal with the Zero Length packet problem, I hope */ | |
8364 | + odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; | |
8365 | + | |
8366 | + /* Send the URB on its merry way. */ | |
8367 | + result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); | |
8368 | + if (result) { | |
8369 | + dev_warn(&odev->parent->interface->dev, | |
8370 | + "failed mux_bulk_tx_urb %d\n", result); | |
8371 | + net->stats.tx_errors++; | |
8372 | + netif_start_queue(net); | |
8373 | + } else { | |
8374 | + net->stats.tx_packets++; | |
8375 | + net->stats.tx_bytes += skb->len; | |
8376 | + } | |
8377 | + dev_kfree_skb(skb); | |
8378 | + /* we're done */ | |
8379 | + return NETDEV_TX_OK; | |
8380 | +} | |
8381 | + | |
8382 | +static const struct ethtool_ops ops = { | |
8383 | + .get_link = ethtool_op_get_link | |
8384 | +}; | |
8385 | + | |
8386 | +/* called when a packet did not ack after watchdogtimeout */ | |
8387 | +static void hso_net_tx_timeout(struct net_device *net) | |
8388 | +{ | |
8389 | + struct hso_net *odev = netdev_priv(net); | |
8390 | + | |
8391 | + if (!odev) | |
8392 | + return; | |
8393 | + | |
8394 | + /* Tell syslog we are hosed. */ | |
8395 | + dev_warn(&net->dev, "Tx timed out.\n"); | |
8396 | + | |
8397 | + /* Tear the waiting frame off the list */ | |
8398 | + if (odev->mux_bulk_tx_urb && | |
8399 | + (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) | |
8400 | + usb_unlink_urb(odev->mux_bulk_tx_urb); | |
8401 | + | |
8402 | + /* Update statistics */ | |
8403 | + net->stats.tx_errors++; | |
8404 | +} | |
8405 | + | |
8406 | +/* make a real packet from the received USB buffer */ | |
8407 | +static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, | |
8408 | + unsigned int count, unsigned char is_eop) | |
8409 | +{ | |
8410 | + unsigned short temp_bytes; | |
8411 | + unsigned short buffer_offset = 0; | |
8412 | + unsigned short frame_len; | |
8413 | + unsigned char *tmp_rx_buf; | |
8414 | + | |
8415 | + /* log if needed */ | |
8416 | + D1("Rx %d bytes", count); | |
8417 | + DUMP(ip_pkt, min(128, (int)count)); | |
8418 | + | |
8419 | + while (count) { | |
8420 | + switch (odev->rx_parse_state) { | |
8421 | + case WAIT_IP: | |
8422 | + /* waiting for IP header. */ | |
8423 | + /* wanted bytes - size of ip header */ | |
8424 | + temp_bytes = | |
8425 | + (count < | |
8426 | + odev->rx_buf_missing) ? count : odev-> | |
8427 | + rx_buf_missing; | |
8428 | + | |
8429 | + memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + | |
8430 | + odev->rx_buf_size, ip_pkt + buffer_offset, | |
8431 | + temp_bytes); | |
8432 | + | |
8433 | + odev->rx_buf_size += temp_bytes; | |
8434 | + buffer_offset += temp_bytes; | |
8435 | + odev->rx_buf_missing -= temp_bytes; | |
8436 | + count -= temp_bytes; | |
8437 | + | |
8438 | + if (!odev->rx_buf_missing) { | |
8439 | + /* header is complete allocate an sk_buffer and | |
8440 | + * continue to WAIT_DATA */ | |
8441 | + frame_len = ntohs(odev->rx_ip_hdr.tot_len); | |
8442 | + | |
8443 | + if ((frame_len > DEFAULT_MRU) || | |
8444 | + (frame_len < sizeof(struct iphdr))) { | |
8445 | + dev_err(&odev->net->dev, | |
8446 | + "Invalid frame (%d) length\n", | |
8447 | + frame_len); | |
8448 | + odev->rx_parse_state = WAIT_SYNC; | |
8449 | + continue; | |
8450 | + } | |
8451 | + /* Allocate an sk_buff */ | |
8452 | + odev->skb_rx_buf = netdev_alloc_skb(odev->net, | |
8453 | + frame_len); | |
8454 | + if (!odev->skb_rx_buf) { | |
8455 | + /* We got no receive buffer. */ | |
8456 | + D1("could not allocate memory"); | |
8457 | + odev->rx_parse_state = WAIT_SYNC; | |
8458 | + return; | |
8459 | + } | |
8460 | + | |
8461 | + /* Copy what we got so far. make room for iphdr | |
8462 | + * after tail. */ | |
8463 | + tmp_rx_buf = | |
8464 | + skb_put(odev->skb_rx_buf, | |
8465 | + sizeof(struct iphdr)); | |
8466 | + memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), | |
8467 | + sizeof(struct iphdr)); | |
8468 | + | |
8469 | + /* ETH_HLEN */ | |
8470 | + odev->rx_buf_size = sizeof(struct iphdr); | |
8471 | + | |
8472 | + /* Filip actually use .tot_len */ | |
8473 | + odev->rx_buf_missing = | |
8474 | + frame_len - sizeof(struct iphdr); | |
8475 | + odev->rx_parse_state = WAIT_DATA; | |
8476 | + } | |
8477 | + break; | |
8478 | + | |
8479 | + case WAIT_DATA: | |
8480 | + temp_bytes = (count < odev->rx_buf_missing) | |
8481 | + ? count : odev->rx_buf_missing; | |
8482 | + | |
8483 | + /* Copy the rest of the bytes that are left in the | |
8484 | + * buffer into the waiting sk_buf. */ | |
8485 | + /* Make room for temp_bytes after tail. */ | |
8486 | + tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); | |
8487 | + memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); | |
8488 | + | |
8489 | + odev->rx_buf_missing -= temp_bytes; | |
8490 | + count -= temp_bytes; | |
8491 | + buffer_offset += temp_bytes; | |
8492 | + odev->rx_buf_size += temp_bytes; | |
8493 | + if (!odev->rx_buf_missing) { | |
8494 | + /* Packet is complete. Inject into stack. */ | |
8495 | + /* We have IP packet here */ | |
8496 | + odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); | |
8497 | + skb_reset_mac_header(odev->skb_rx_buf); | |
8498 | + | |
8499 | + /* Ship it off to the kernel */ | |
8500 | + netif_rx(odev->skb_rx_buf); | |
8501 | + /* No longer our buffer. */ | |
8502 | + odev->skb_rx_buf = NULL; | |
8503 | + | |
8504 | + /* update out statistics */ | |
8505 | + odev->net->stats.rx_packets++; | |
8506 | + | |
8507 | + odev->net->stats.rx_bytes += odev->rx_buf_size; | |
8508 | + | |
8509 | + odev->rx_buf_size = 0; | |
8510 | + odev->rx_buf_missing = sizeof(struct iphdr); | |
8511 | + odev->rx_parse_state = WAIT_IP; | |
8512 | + } | |
8513 | + break; | |
8514 | + | |
8515 | + case WAIT_SYNC: | |
8516 | + D1(" W_S"); | |
8517 | + count = 0; | |
8518 | + break; | |
8519 | + default: | |
8520 | + D1(" "); | |
8521 | + count--; | |
8522 | + break; | |
8523 | + } | |
8524 | + } | |
8525 | + | |
8526 | + /* Recovery mechanism for WAIT_SYNC state. */ | |
8527 | + if (is_eop) { | |
8528 | + if (odev->rx_parse_state == WAIT_SYNC) { | |
8529 | + odev->rx_parse_state = WAIT_IP; | |
8530 | + odev->rx_buf_size = 0; | |
8531 | + odev->rx_buf_missing = sizeof(struct iphdr); | |
8532 | + } | |
8533 | + } | |
8534 | +} | |
8535 | + | |
8536 | +static void fix_crc_bug(struct urb *urb, __le16 max_packet_size) | |
8537 | +{ | |
8538 | + static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; | |
8539 | + u32 rest = urb->actual_length % le16_to_cpu(max_packet_size); | |
8540 | + | |
8541 | + if (((rest == 5) || (rest == 6)) && | |
8542 | + !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4, | |
8543 | + crc_check, 4)) { | |
8544 | + urb->actual_length -= 4; | |
8545 | + } | |
8546 | +} | |
8547 | + | |
8548 | +/* Moving data from usb to kernel (in interrupt state) */ | |
8549 | +static void read_bulk_callback(struct urb *urb) | |
8550 | +{ | |
8551 | + struct hso_net *odev = urb->context; | |
8552 | + struct net_device *net; | |
8553 | + int result; | |
8554 | + int status = urb->status; | |
8555 | + | |
8556 | + /* is al ok? (Filip: Who's Al ?) */ | |
8557 | + if (status) { | |
8558 | + handle_usb_error(status, __func__, odev->parent); | |
8559 | + return; | |
8560 | + } | |
8561 | + | |
8562 | + /* Sanity check */ | |
8563 | + if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { | |
8564 | + D1("BULK IN callback but driver is not active!"); | |
8565 | + return; | |
8566 | + } | |
8567 | + usb_mark_last_busy(urb->dev); | |
8568 | + | |
8569 | + net = odev->net; | |
8570 | + | |
8571 | + if (!netif_device_present(net)) { | |
8572 | + /* Somebody killed our network interface... */ | |
8573 | + return; | |
8574 | + } | |
8575 | + | |
8576 | + if (odev->parent->port_spec & HSO_INFO_CRC_BUG) | |
8577 | + fix_crc_bug(urb, odev->in_endp->wMaxPacketSize); | |
8578 | + | |
8579 | + /* do we even have a packet? */ | |
8580 | + if (urb->actual_length) { | |
8581 | + /* Handle the IP stream, add header and push it onto network | |
8582 | + * stack if the packet is complete. */ | |
8583 | + spin_lock(&odev->net_lock); | |
8584 | + packetizeRx(odev, urb->transfer_buffer, urb->actual_length, | |
8585 | + (urb->transfer_buffer_length > | |
8586 | + urb->actual_length) ? 1 : 0); | |
8587 | + spin_unlock(&odev->net_lock); | |
8588 | + } | |
8589 | + | |
8590 | + /* We are done with this URB, resubmit it. Prep the USB to wait for | |
8591 | + * another frame. Reuse same as received. */ | |
8592 | + usb_fill_bulk_urb(urb, | |
8593 | + odev->parent->usb, | |
8594 | + usb_rcvbulkpipe(odev->parent->usb, | |
8595 | + odev->in_endp-> | |
8596 | + bEndpointAddress & 0x7F), | |
8597 | + urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, | |
8598 | + read_bulk_callback, odev); | |
8599 | + | |
8600 | + /* Give this to the USB subsystem so it can tell us when more data | |
8601 | + * arrives. */ | |
8602 | + result = usb_submit_urb(urb, GFP_ATOMIC); | |
8603 | + if (result) | |
8604 | + dev_warn(&odev->parent->interface->dev, | |
8605 | + "%s failed submit mux_bulk_rx_urb %d\n", __func__, | |
8606 | + result); | |
8607 | +} | |
8608 | + | |
8609 | +/* Serial driver functions */ | |
8610 | + | |
8611 | +static void hso_init_termios(struct ktermios *termios) | |
8612 | +{ | |
8613 | + /* | |
8614 | + * The default requirements for this device are: | |
8615 | + */ | |
8616 | + termios->c_iflag &= | |
8617 | + ~(IGNBRK /* disable ignore break */ | |
8618 | + | BRKINT /* disable break causes interrupt */ | |
8619 | + | PARMRK /* disable mark parity errors */ | |
8620 | + | ISTRIP /* disable clear high bit of input characters */ | |
8621 | + | INLCR /* disable translate NL to CR */ | |
8622 | + | IGNCR /* disable ignore CR */ | |
8623 | + | ICRNL /* disable translate CR to NL */ | |
8624 | + | IXON); /* disable enable XON/XOFF flow control */ | |
8625 | + | |
8626 | + /* disable postprocess output characters */ | |
8627 | + termios->c_oflag &= ~OPOST; | |
8628 | + | |
8629 | + termios->c_lflag &= | |
8630 | + ~(ECHO /* disable echo input characters */ | |
8631 | + | ECHONL /* disable echo new line */ | |
8632 | + | ICANON /* disable erase, kill, werase, and rprnt | |
8633 | + special characters */ | |
8634 | + | ISIG /* disable interrupt, quit, and suspend special | |
8635 | + characters */ | |
8636 | + | IEXTEN); /* disable non-POSIX special characters */ | |
8637 | + | |
8638 | + termios->c_cflag &= | |
8639 | + ~(CSIZE /* no size */ | |
8640 | + | PARENB /* disable parity bit */ | |
8641 | + | CBAUD /* clear current baud rate */ | |
8642 | + | CBAUDEX); /* clear current buad rate */ | |
8643 | + | |
8644 | + termios->c_cflag |= CS8; /* character size 8 bits */ | |
8645 | + | |
8646 | + /* baud rate 115200 */ | |
8647 | + tty_termios_encode_baud_rate(termios, 115200, 115200); | |
8648 | +} | |
8649 | + | |
8650 | +static void _hso_serial_set_termios(struct tty_struct *tty, | |
8651 | + struct ktermios *old) | |
8652 | +{ | |
8653 | + struct hso_serial *serial = tty->driver_data; | |
8654 | + | |
8655 | + if (!serial) { | |
8656 | + printk(KERN_ERR "%s: no tty structures", __func__); | |
8657 | + return; | |
8658 | + } | |
8659 | + | |
8660 | + D4("port %d", serial->minor); | |
8661 | + | |
8662 | + /* | |
8663 | + * Fix up unsupported bits | |
8664 | + */ | |
8665 | + tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ | |
8666 | + | |
8667 | + tty->termios.c_cflag &= | |
8668 | + ~(CSIZE /* no size */ | |
8669 | + | PARENB /* disable parity bit */ | |
8670 | + | CBAUD /* clear current baud rate */ | |
8671 | + | CBAUDEX); /* clear current buad rate */ | |
8672 | + | |
8673 | + tty->termios.c_cflag |= CS8; /* character size 8 bits */ | |
8674 | + | |
8675 | + /* baud rate 115200 */ | |
8676 | + tty_encode_baud_rate(tty, 115200, 115200); | |
8677 | +} | |
8678 | + | |
8679 | +static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) | |
8680 | +{ | |
8681 | + int result; | |
8682 | + /* We are done with this URB, resubmit it. Prep the USB to wait for | |
8683 | + * another frame */ | |
8684 | + usb_fill_bulk_urb(urb, serial->parent->usb, | |
8685 | + usb_rcvbulkpipe(serial->parent->usb, | |
8686 | + serial->in_endp-> | |
8687 | + bEndpointAddress & 0x7F), | |
8688 | + urb->transfer_buffer, serial->rx_data_length, | |
8689 | + hso_std_serial_read_bulk_callback, serial); | |
8690 | + /* Give this to the USB subsystem so it can tell us when more data | |
8691 | + * arrives. */ | |
8692 | + result = usb_submit_urb(urb, GFP_ATOMIC); | |
8693 | + if (result) { | |
8694 | + dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", | |
8695 | + __func__, result); | |
8696 | + } | |
8697 | +} | |
8698 | + | |
8699 | + | |
8700 | + | |
8701 | + | |
8702 | +static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial) | |
8703 | +{ | |
8704 | + int count; | |
8705 | + struct urb *curr_urb; | |
8706 | + | |
8707 | + while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { | |
8708 | + curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; | |
8709 | + count = put_rxbuf_data(curr_urb, serial); | |
8710 | + if (count == -1) | |
8711 | + return; | |
8712 | + if (count == 0) { | |
8713 | + serial->curr_rx_urb_idx++; | |
8714 | + if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) | |
8715 | + serial->curr_rx_urb_idx = 0; | |
8716 | + hso_resubmit_rx_bulk_urb(serial, curr_urb); | |
8717 | + } | |
8718 | + } | |
8719 | +} | |
8720 | + | |
8721 | +static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) | |
8722 | +{ | |
8723 | + int count = 0; | |
8724 | + struct urb *urb; | |
8725 | + | |
8726 | + urb = serial->rx_urb[0]; | |
8727 | + if (atomic_read(&serial->port.count) > 0) { | |
8728 | + count = put_rxbuf_data(urb, serial); | |
8729 | + if (count == -1) | |
8730 | + return; | |
8731 | + } | |
8732 | + /* Re issue a read as long as we receive data. */ | |
8733 | + | |
8734 | + if (count == 0 && ((urb->actual_length != 0) || | |
8735 | + (serial->rx_state == RX_PENDING))) { | |
8736 | + serial->rx_state = RX_SENT; | |
8737 | + hso_mux_serial_read(serial); | |
8738 | + } else | |
8739 | + serial->rx_state = RX_IDLE; | |
8740 | +} | |
8741 | + | |
8742 | + | |
8743 | +/* read callback for Diag and CS port */ | |
8744 | +static void hso_std_serial_read_bulk_callback(struct urb *urb) | |
8745 | +{ | |
8746 | + struct hso_serial *serial = urb->context; | |
8747 | + int status = urb->status; | |
8748 | + | |
8749 | + D4("\n--- Got serial_read_bulk callback %02x ---", status); | |
8750 | + | |
8751 | + /* sanity check */ | |
8752 | + if (!serial) { | |
8753 | + D1("serial == NULL"); | |
8754 | + return; | |
8755 | + } | |
8756 | + if (status) { | |
8757 | + handle_usb_error(status, __func__, serial->parent); | |
8758 | + return; | |
8759 | + } | |
8760 | + | |
8761 | + D1("Actual length = %d\n", urb->actual_length); | |
8762 | + DUMP1(urb->transfer_buffer, urb->actual_length); | |
8763 | + | |
8764 | + /* Anyone listening? */ | |
8765 | + if (atomic_read(&serial->port.count) == 0) | |
8766 | + return; | |
8767 | + | |
8768 | + if (serial->parent->port_spec & HSO_INFO_CRC_BUG) | |
8769 | + fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); | |
8770 | + /* Valid data, handle RX data */ | |
8771 | + spin_lock(&serial->serial_lock); | |
8772 | + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; | |
8773 | + put_rxbuf_data_and_resubmit_bulk_urb(serial); | |
8774 | + spin_unlock(&serial->serial_lock); | |
8775 | +} | |
8776 | + | |
8777 | +/* | |
8778 | + * This needs to be a tasklet otherwise we will | |
8779 | + * end up recursively calling this function. | |
8780 | + */ | |
8781 | +static void hso_unthrottle_tasklet(struct hso_serial *serial) | |
8782 | +{ | |
8783 | + unsigned long flags; | |
8784 | + | |
8785 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
8786 | + if ((serial->parent->port_spec & HSO_INTF_MUX)) | |
8787 | + put_rxbuf_data_and_resubmit_ctrl_urb(serial); | |
8788 | + else | |
8789 | + put_rxbuf_data_and_resubmit_bulk_urb(serial); | |
8790 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
8791 | +} | |
8792 | + | |
8793 | +static void hso_unthrottle(struct tty_struct *tty) | |
8794 | +{ | |
8795 | + struct hso_serial *serial = tty->driver_data; | |
8796 | + | |
8797 | + tasklet_hi_schedule(&serial->unthrottle_tasklet); | |
8798 | +} | |
8799 | + | |
8800 | +/* open the requested serial port */ | |
8801 | +static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |
8802 | +{ | |
8803 | + struct hso_serial *serial = get_serial_by_index(tty->index); | |
8804 | + int result; | |
8805 | + | |
8806 | + /* sanity check */ | |
8807 | + if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { | |
8808 | + WARN_ON(1); | |
8809 | + tty->driver_data = NULL; | |
8810 | + D1("Failed to open port"); | |
8811 | + return -ENODEV; | |
8812 | + } | |
8813 | + | |
8814 | + mutex_lock(&serial->parent->mutex); | |
8815 | + result = usb_autopm_get_interface(serial->parent->interface); | |
8816 | + if (result < 0) | |
8817 | + goto err_out; | |
8818 | + | |
8819 | + D1("Opening %d", serial->minor); | |
8820 | + kref_get(&serial->parent->ref); | |
8821 | + | |
8822 | + /* setup */ | |
8823 | + tty->driver_data = serial; | |
8824 | + tty_port_tty_set(&serial->port, tty); | |
8825 | + | |
8826 | + /* check for port already opened, if not set the termios */ | |
8827 | + if (atomic_inc_return(&serial->port.count) == 1) { | |
8828 | + serial->rx_state = RX_IDLE; | |
8829 | + /* Force default termio settings */ | |
8830 | + _hso_serial_set_termios(tty, NULL); | |
8831 | + tasklet_init(&serial->unthrottle_tasklet, | |
8832 | + (void (*)(unsigned long))hso_unthrottle_tasklet, | |
8833 | + (unsigned long)serial); | |
8834 | + result = hso_start_serial_device(serial->parent, GFP_KERNEL); | |
8835 | + if (result) { | |
8836 | + hso_stop_serial_device(serial->parent); | |
8837 | + atomic_dec(&serial->port.count); | |
8838 | + kref_put(&serial->parent->ref, hso_serial_ref_free); | |
8839 | + } | |
8840 | + } else { | |
8841 | + D1("Port was already open"); | |
8842 | + } | |
8843 | + | |
8844 | + usb_autopm_put_interface(serial->parent->interface); | |
8845 | + | |
8846 | + /* done */ | |
8847 | + if (result) | |
8848 | + hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0); | |
8849 | +err_out: | |
8850 | + mutex_unlock(&serial->parent->mutex); | |
8851 | + return result; | |
8852 | +} | |
8853 | + | |
8854 | +/* close the requested serial port */ | |
8855 | +static void hso_serial_close(struct tty_struct *tty, struct file *filp) | |
8856 | +{ | |
8857 | + struct hso_serial *serial = tty->driver_data; | |
8858 | + u8 usb_gone; | |
8859 | + | |
8860 | + D1("Closing serial port"); | |
8861 | + | |
8862 | + /* Open failed, no close cleanup required */ | |
8863 | + if (serial == NULL) | |
8864 | + return; | |
8865 | + | |
8866 | + mutex_lock(&serial->parent->mutex); | |
8867 | + usb_gone = serial->parent->usb_gone; | |
8868 | + | |
8869 | + if (!usb_gone) | |
8870 | + usb_autopm_get_interface(serial->parent->interface); | |
8871 | + | |
8872 | + /* reset the rts and dtr */ | |
8873 | + /* do the actual close */ | |
8874 | + atomic_dec(&serial->port.count); | |
8875 | + | |
8876 | + if (atomic_read(&serial->port.count) <= 0) { | |
8877 | + atomic_set(&serial->port.count, 0); | |
8878 | + tty_port_tty_set(&serial->port, NULL); | |
8879 | + if (!usb_gone) | |
8880 | + hso_stop_serial_device(serial->parent); | |
8881 | + tasklet_kill(&serial->unthrottle_tasklet); | |
8882 | + } | |
8883 | + | |
8884 | + if (!usb_gone) | |
8885 | + usb_autopm_put_interface(serial->parent->interface); | |
8886 | + | |
8887 | + mutex_unlock(&serial->parent->mutex); | |
8888 | + | |
8889 | + kref_put(&serial->parent->ref, hso_serial_ref_free); | |
8890 | +} | |
8891 | + | |
8892 | +/* close the requested serial port */ | |
8893 | +static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, | |
8894 | + int count) | |
8895 | +{ | |
8896 | + struct hso_serial *serial = tty->driver_data; | |
8897 | + int space, tx_bytes; | |
8898 | + unsigned long flags; | |
8899 | + | |
8900 | + /* sanity check */ | |
8901 | + if (serial == NULL) { | |
8902 | + printk(KERN_ERR "%s: serial is NULL\n", __func__); | |
8903 | + return -ENODEV; | |
8904 | + } | |
8905 | + | |
8906 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
8907 | + | |
8908 | + space = serial->tx_data_length - serial->tx_buffer_count; | |
8909 | + tx_bytes = (count < space) ? count : space; | |
8910 | + | |
8911 | + if (!tx_bytes) | |
8912 | + goto out; | |
8913 | + | |
8914 | + memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes); | |
8915 | + serial->tx_buffer_count += tx_bytes; | |
8916 | + | |
8917 | +out: | |
8918 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
8919 | + | |
8920 | + hso_kick_transmit(serial); | |
8921 | + /* done */ | |
8922 | + return tx_bytes; | |
8923 | +} | |
8924 | + | |
8925 | +/* how much room is there for writing */ | |
8926 | +static int hso_serial_write_room(struct tty_struct *tty) | |
8927 | +{ | |
8928 | + struct hso_serial *serial = tty->driver_data; | |
8929 | + int room; | |
8930 | + unsigned long flags; | |
8931 | + | |
8932 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
8933 | + room = serial->tx_data_length - serial->tx_buffer_count; | |
8934 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
8935 | + | |
8936 | + /* return free room */ | |
8937 | + return room; | |
8938 | +} | |
8939 | + | |
8940 | +/* setup the term */ | |
8941 | +static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) | |
8942 | +{ | |
8943 | + struct hso_serial *serial = tty->driver_data; | |
8944 | + unsigned long flags; | |
8945 | + | |
8946 | + if (old) | |
8947 | + D5("Termios called with: cflags new[%d] - old[%d]", | |
8948 | + tty->termios.c_cflag, old->c_cflag); | |
8949 | + | |
8950 | + /* the actual setup */ | |
8951 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
8952 | + if (atomic_read(&serial->port.count)) | |
8953 | + _hso_serial_set_termios(tty, old); | |
8954 | + else | |
8955 | + tty->termios = *old; | |
8956 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
8957 | + | |
8958 | + /* done */ | |
8959 | +} | |
8960 | + | |
8961 | +/* how many characters in the buffer */ | |
8962 | +static int hso_serial_chars_in_buffer(struct tty_struct *tty) | |
8963 | +{ | |
8964 | + struct hso_serial *serial = tty->driver_data; | |
8965 | + int chars; | |
8966 | + unsigned long flags; | |
8967 | + | |
8968 | + /* sanity check */ | |
8969 | + if (serial == NULL) | |
8970 | + return 0; | |
8971 | + | |
8972 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
8973 | + chars = serial->tx_buffer_count; | |
8974 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
8975 | + | |
8976 | + return chars; | |
8977 | +} | |
8978 | +static int tiocmget_submit_urb(struct hso_serial *serial, | |
8979 | + struct hso_tiocmget *tiocmget, | |
8980 | + struct usb_device *usb) | |
8981 | +{ | |
8982 | + int result; | |
8983 | + | |
8984 | + if (serial->parent->usb_gone) | |
8985 | + return -ENODEV; | |
8986 | + usb_fill_int_urb(tiocmget->urb, usb, | |
8987 | + usb_rcvintpipe(usb, | |
8988 | + tiocmget->endp-> | |
8989 | + bEndpointAddress & 0x7F), | |
8990 | + &tiocmget->serial_state_notification, | |
8991 | + sizeof(struct hso_serial_state_notification), | |
8992 | + tiocmget_intr_callback, serial, | |
8993 | + tiocmget->endp->bInterval); | |
8994 | + result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); | |
8995 | + if (result) { | |
8996 | + dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, | |
8997 | + result); | |
8998 | + } | |
8999 | + return result; | |
9000 | + | |
9001 | +} | |
9002 | + | |
9003 | +static void tiocmget_intr_callback(struct urb *urb) | |
9004 | +{ | |
9005 | + struct hso_serial *serial = urb->context; | |
9006 | + struct hso_tiocmget *tiocmget; | |
9007 | + int status = urb->status; | |
9008 | + u16 UART_state_bitmap, prev_UART_state_bitmap; | |
9009 | + struct uart_icount *icount; | |
9010 | + struct hso_serial_state_notification *serial_state_notification; | |
9011 | + struct usb_device *usb; | |
9012 | + int if_num; | |
9013 | + | |
9014 | + /* Sanity checks */ | |
9015 | + if (!serial) | |
9016 | + return; | |
9017 | + if (status) { | |
9018 | + handle_usb_error(status, __func__, serial->parent); | |
9019 | + return; | |
9020 | + } | |
9021 | + | |
9022 | + /* tiocmget is only supported on HSO_PORT_MODEM */ | |
9023 | + tiocmget = serial->tiocmget; | |
9024 | + if (!tiocmget) | |
9025 | + return; | |
9026 | + BUG_ON((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM); | |
9027 | + | |
9028 | + usb = serial->parent->usb; | |
9029 | + if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; | |
9030 | + | |
9031 | + /* wIndex should be the USB interface number of the port to which the | |
9032 | + * notification applies, which should always be the Modem port. | |
9033 | + */ | |
9034 | + serial_state_notification = &tiocmget->serial_state_notification; | |
9035 | + if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || | |
9036 | + serial_state_notification->bNotification != B_NOTIFICATION || | |
9037 | + le16_to_cpu(serial_state_notification->wValue) != W_VALUE || | |
9038 | + le16_to_cpu(serial_state_notification->wIndex) != if_num || | |
9039 | + le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { | |
9040 | + dev_warn(&usb->dev, | |
9041 | + "hso received invalid serial state notification\n"); | |
9042 | + DUMP(serial_state_notification, | |
9043 | + sizeof(struct hso_serial_state_notification)); | |
9044 | + } else { | |
9045 | + | |
9046 | + UART_state_bitmap = le16_to_cpu(serial_state_notification-> | |
9047 | + UART_state_bitmap); | |
9048 | + prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; | |
9049 | + icount = &tiocmget->icount; | |
9050 | + spin_lock(&serial->serial_lock); | |
9051 | + if ((UART_state_bitmap & B_OVERRUN) != | |
9052 | + (prev_UART_state_bitmap & B_OVERRUN)) | |
9053 | + icount->parity++; | |
9054 | + if ((UART_state_bitmap & B_PARITY) != | |
9055 | + (prev_UART_state_bitmap & B_PARITY)) | |
9056 | + icount->parity++; | |
9057 | + if ((UART_state_bitmap & B_FRAMING) != | |
9058 | + (prev_UART_state_bitmap & B_FRAMING)) | |
9059 | + icount->frame++; | |
9060 | + if ((UART_state_bitmap & B_RING_SIGNAL) && | |
9061 | + !(prev_UART_state_bitmap & B_RING_SIGNAL)) | |
9062 | + icount->rng++; | |
9063 | + if ((UART_state_bitmap & B_BREAK) != | |
9064 | + (prev_UART_state_bitmap & B_BREAK)) | |
9065 | + icount->brk++; | |
9066 | + if ((UART_state_bitmap & B_TX_CARRIER) != | |
9067 | + (prev_UART_state_bitmap & B_TX_CARRIER)) | |
9068 | + icount->dsr++; | |
9069 | + if ((UART_state_bitmap & B_RX_CARRIER) != | |
9070 | + (prev_UART_state_bitmap & B_RX_CARRIER)) | |
9071 | + icount->dcd++; | |
9072 | + tiocmget->prev_UART_state_bitmap = UART_state_bitmap; | |
9073 | + spin_unlock(&serial->serial_lock); | |
9074 | + tiocmget->intr_completed = 1; | |
9075 | + wake_up_interruptible(&tiocmget->waitq); | |
9076 | + } | |
9077 | + memset(serial_state_notification, 0, | |
9078 | + sizeof(struct hso_serial_state_notification)); | |
9079 | + tiocmget_submit_urb(serial, | |
9080 | + tiocmget, | |
9081 | + serial->parent->usb); | |
9082 | +} | |
9083 | + | |
9084 | +/* | |
9085 | + * next few functions largely stolen from drivers/serial/serial_core.c | |
9086 | + */ | |
9087 | +/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | |
9088 | + * - mask passed in arg for lines of interest | |
9089 | + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | |
9090 | + * Caller should use TIOCGICOUNT to see which one it was | |
9091 | + */ | |
9092 | +static int | |
9093 | +hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) | |
9094 | +{ | |
9095 | + DECLARE_WAITQUEUE(wait, current); | |
9096 | + struct uart_icount cprev, cnow; | |
9097 | + struct hso_tiocmget *tiocmget; | |
9098 | + int ret; | |
9099 | + | |
9100 | + tiocmget = serial->tiocmget; | |
9101 | + if (!tiocmget) | |
9102 | + return -ENOENT; | |
9103 | + /* | |
9104 | + * note the counters on entry | |
9105 | + */ | |
9106 | + spin_lock_irq(&serial->serial_lock); | |
9107 | + memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); | |
9108 | + spin_unlock_irq(&serial->serial_lock); | |
9109 | + add_wait_queue(&tiocmget->waitq, &wait); | |
9110 | + for (;;) { | |
9111 | + spin_lock_irq(&serial->serial_lock); | |
9112 | + memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); | |
9113 | + spin_unlock_irq(&serial->serial_lock); | |
9114 | + set_current_state(TASK_INTERRUPTIBLE); | |
9115 | + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | |
9116 | + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | |
9117 | + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { | |
9118 | + ret = 0; | |
9119 | + break; | |
9120 | + } | |
9121 | + schedule(); | |
9122 | + /* see if a signal did it */ | |
9123 | + if (signal_pending(current)) { | |
9124 | + ret = -ERESTARTSYS; | |
9125 | + break; | |
9126 | + } | |
9127 | + cprev = cnow; | |
9128 | + } | |
9129 | + current->state = TASK_RUNNING; | |
9130 | + remove_wait_queue(&tiocmget->waitq, &wait); | |
9131 | + | |
9132 | + return ret; | |
9133 | +} | |
9134 | + | |
9135 | +/* | |
9136 | + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | |
9137 | + * Return: write counters to the user passed counter struct | |
9138 | + * NB: both 1->0 and 0->1 transitions are counted except for | |
9139 | + * RI where only 0->1 is counted. | |
9140 | + */ | |
9141 | +static int hso_get_count(struct tty_struct *tty, | |
9142 | + struct serial_icounter_struct *icount) | |
9143 | +{ | |
9144 | + struct uart_icount cnow; | |
9145 | + struct hso_serial *serial = tty->driver_data; | |
9146 | + struct hso_tiocmget *tiocmget = serial->tiocmget; | |
9147 | + | |
9148 | + memset(icount, 0, sizeof(struct serial_icounter_struct)); | |
9149 | + | |
9150 | + if (!tiocmget) | |
9151 | + return -ENOENT; | |
9152 | + spin_lock_irq(&serial->serial_lock); | |
9153 | + memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); | |
9154 | + spin_unlock_irq(&serial->serial_lock); | |
9155 | + | |
9156 | + icount->cts = cnow.cts; | |
9157 | + icount->dsr = cnow.dsr; | |
9158 | + icount->rng = cnow.rng; | |
9159 | + icount->dcd = cnow.dcd; | |
9160 | + icount->rx = cnow.rx; | |
9161 | + icount->tx = cnow.tx; | |
9162 | + icount->frame = cnow.frame; | |
9163 | + icount->overrun = cnow.overrun; | |
9164 | + icount->parity = cnow.parity; | |
9165 | + icount->brk = cnow.brk; | |
9166 | + icount->buf_overrun = cnow.buf_overrun; | |
9167 | + | |
9168 | + return 0; | |
9169 | +} | |
9170 | + | |
9171 | + | |
9172 | +static int hso_serial_tiocmget(struct tty_struct *tty) | |
9173 | +{ | |
9174 | + int retval; | |
9175 | + struct hso_serial *serial = tty->driver_data; | |
9176 | + struct hso_tiocmget *tiocmget; | |
9177 | + u16 UART_state_bitmap; | |
9178 | + | |
9179 | + /* sanity check */ | |
9180 | + if (!serial) { | |
9181 | + D1("no tty structures"); | |
9182 | + return -EINVAL; | |
9183 | + } | |
9184 | + spin_lock_irq(&serial->serial_lock); | |
9185 | + retval = ((serial->rts_state) ? TIOCM_RTS : 0) | | |
9186 | + ((serial->dtr_state) ? TIOCM_DTR : 0); | |
9187 | + tiocmget = serial->tiocmget; | |
9188 | + if (tiocmget) { | |
9189 | + | |
9190 | + UART_state_bitmap = le16_to_cpu( | |
9191 | + tiocmget->prev_UART_state_bitmap); | |
9192 | + if (UART_state_bitmap & B_RING_SIGNAL) | |
9193 | + retval |= TIOCM_RNG; | |
9194 | + if (UART_state_bitmap & B_RX_CARRIER) | |
9195 | + retval |= TIOCM_CD; | |
9196 | + if (UART_state_bitmap & B_TX_CARRIER) | |
9197 | + retval |= TIOCM_DSR; | |
9198 | + } | |
9199 | + spin_unlock_irq(&serial->serial_lock); | |
9200 | + return retval; | |
9201 | +} | |
9202 | + | |
9203 | +static int hso_serial_tiocmset(struct tty_struct *tty, | |
9204 | + unsigned int set, unsigned int clear) | |
9205 | +{ | |
9206 | + int val = 0; | |
9207 | + unsigned long flags; | |
9208 | + int if_num; | |
9209 | + struct hso_serial *serial = tty->driver_data; | |
9210 | + | |
9211 | + /* sanity check */ | |
9212 | + if (!serial) { | |
9213 | + D1("no tty structures"); | |
9214 | + return -EINVAL; | |
9215 | + } | |
9216 | + | |
9217 | + if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM) | |
9218 | + return -EINVAL; | |
9219 | + | |
9220 | + if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; | |
9221 | + | |
9222 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
9223 | + if (set & TIOCM_RTS) | |
9224 | + serial->rts_state = 1; | |
9225 | + if (set & TIOCM_DTR) | |
9226 | + serial->dtr_state = 1; | |
9227 | + | |
9228 | + if (clear & TIOCM_RTS) | |
9229 | + serial->rts_state = 0; | |
9230 | + if (clear & TIOCM_DTR) | |
9231 | + serial->dtr_state = 0; | |
9232 | + | |
9233 | + if (serial->dtr_state) | |
9234 | + val |= 0x01; | |
9235 | + if (serial->rts_state) | |
9236 | + val |= 0x02; | |
9237 | + | |
9238 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
9239 | + | |
9240 | + return usb_control_msg(serial->parent->usb, | |
9241 | + usb_rcvctrlpipe(serial->parent->usb, 0), 0x22, | |
9242 | + 0x21, val, if_num, NULL, 0, | |
9243 | + USB_CTRL_SET_TIMEOUT); | |
9244 | +} | |
9245 | + | |
9246 | +static int hso_serial_ioctl(struct tty_struct *tty, | |
9247 | + unsigned int cmd, unsigned long arg) | |
9248 | +{ | |
9249 | + struct hso_serial *serial = tty->driver_data; | |
9250 | + int ret = 0; | |
9251 | + D4("IOCTL cmd: %d, arg: %ld", cmd, arg); | |
9252 | + | |
9253 | + if (!serial) | |
9254 | + return -ENODEV; | |
9255 | + switch (cmd) { | |
9256 | + case TIOCMIWAIT: | |
9257 | + ret = hso_wait_modem_status(serial, arg); | |
9258 | + break; | |
9259 | + default: | |
9260 | + ret = -ENOIOCTLCMD; | |
9261 | + break; | |
9262 | + } | |
9263 | + return ret; | |
9264 | +} | |
9265 | + | |
9266 | + | |
9267 | +/* starts a transmit */ | |
9268 | +static void hso_kick_transmit(struct hso_serial *serial) | |
9269 | +{ | |
9270 | + u8 *temp; | |
9271 | + unsigned long flags; | |
9272 | + int res; | |
9273 | + | |
9274 | + spin_lock_irqsave(&serial->serial_lock, flags); | |
9275 | + if (!serial->tx_buffer_count) | |
9276 | + goto out; | |
9277 | + | |
9278 | + if (serial->tx_urb_used) | |
9279 | + goto out; | |
9280 | + | |
9281 | + /* Wakeup USB interface if necessary */ | |
9282 | + if (hso_get_activity(serial->parent) == -EAGAIN) | |
9283 | + goto out; | |
9284 | + | |
9285 | + /* Switch pointers around to avoid memcpy */ | |
9286 | + temp = serial->tx_buffer; | |
9287 | + serial->tx_buffer = serial->tx_data; | |
9288 | + serial->tx_data = temp; | |
9289 | + serial->tx_data_count = serial->tx_buffer_count; | |
9290 | + serial->tx_buffer_count = 0; | |
9291 | + | |
9292 | + /* If temp is set, it means we switched buffers */ | |
9293 | + if (temp && serial->write_data) { | |
9294 | + res = serial->write_data(serial); | |
9295 | + if (res >= 0) | |
9296 | + serial->tx_urb_used = 1; | |
9297 | + } | |
9298 | +out: | |
9299 | + spin_unlock_irqrestore(&serial->serial_lock, flags); | |
9300 | +} | |
9301 | + | |
9302 | +/* make a request (for reading and writing data to muxed serial port) */ | |
9303 | +static int mux_device_request(struct hso_serial *serial, u8 type, u16 port, | |
9304 | + struct urb *ctrl_urb, | |
9305 | + struct usb_ctrlrequest *ctrl_req, | |
9306 | + u8 *ctrl_urb_data, u32 size) | |
9307 | +{ | |
9308 | + int result; | |
9309 | + int pipe; | |
9310 | + | |
9311 | + /* Sanity check */ | |
9312 | + if (!serial || !ctrl_urb || !ctrl_req) { | |
9313 | + printk(KERN_ERR "%s: Wrong arguments\n", __func__); | |
9314 | + return -EINVAL; | |
9315 | + } | |
9316 | + | |
9317 | + /* initialize */ | |
9318 | + ctrl_req->wValue = 0; | |
9319 | + ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port)); | |
9320 | + ctrl_req->wLength = cpu_to_le16(size); | |
9321 | + | |
9322 | + if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) { | |
9323 | + /* Reading command */ | |
9324 | + ctrl_req->bRequestType = USB_DIR_IN | | |
9325 | + USB_TYPE_OPTION_VENDOR | | |
9326 | + USB_RECIP_INTERFACE; | |
9327 | + ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; | |
9328 | + pipe = usb_rcvctrlpipe(serial->parent->usb, 0); | |
9329 | + } else { | |
9330 | + /* Writing command */ | |
9331 | + ctrl_req->bRequestType = USB_DIR_OUT | | |
9332 | + USB_TYPE_OPTION_VENDOR | | |
9333 | + USB_RECIP_INTERFACE; | |
9334 | + ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; | |
9335 | + pipe = usb_sndctrlpipe(serial->parent->usb, 0); | |
9336 | + } | |
9337 | + /* syslog */ | |
9338 | + D2("%s command (%02x) len: %d, port: %d", | |
9339 | + type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write", | |
9340 | + ctrl_req->bRequestType, ctrl_req->wLength, port); | |
9341 | + | |
9342 | + /* Load ctrl urb */ | |
9343 | + ctrl_urb->transfer_flags = 0; | |
9344 | + usb_fill_control_urb(ctrl_urb, | |
9345 | + serial->parent->usb, | |
9346 | + pipe, | |
9347 | + (u8 *) ctrl_req, | |
9348 | + ctrl_urb_data, size, ctrl_callback, serial); | |
9349 | + /* Send it on merry way */ | |
9350 | + result = usb_submit_urb(ctrl_urb, GFP_ATOMIC); | |
9351 | + if (result) { | |
9352 | + dev_err(&ctrl_urb->dev->dev, | |
9353 | + "%s failed submit ctrl_urb %d type %d\n", __func__, | |
9354 | + result, type); | |
9355 | + return result; | |
9356 | + } | |
9357 | + | |
9358 | + /* done */ | |
9359 | + return size; | |
9360 | +} | |
9361 | + | |
9362 | +/* called by intr_callback when read occurs */ | |
9363 | +static int hso_mux_serial_read(struct hso_serial *serial) | |
9364 | +{ | |
9365 | + if (!serial) | |
9366 | + return -EINVAL; | |
9367 | + | |
9368 | + /* clean data */ | |
9369 | + memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE); | |
9370 | + /* make the request */ | |
9371 | + | |
9372 | + if (serial->num_rx_urbs != 1) { | |
9373 | + dev_err(&serial->parent->interface->dev, | |
9374 | + "ERROR: mux'd reads with multiple buffers " | |
9375 | + "not possible\n"); | |
9376 | + return 0; | |
9377 | + } | |
9378 | + return mux_device_request(serial, | |
9379 | + USB_CDC_GET_ENCAPSULATED_RESPONSE, | |
9380 | + serial->parent->port_spec & HSO_PORT_MASK, | |
9381 | + serial->rx_urb[0], | |
9382 | + &serial->ctrl_req_rx, | |
9383 | + serial->rx_data[0], serial->rx_data_length); | |
9384 | +} | |
9385 | + | |
9386 | +/* used for muxed serial port callback (muxed serial read) */ | |
9387 | +static void intr_callback(struct urb *urb) | |
9388 | +{ | |
9389 | + struct hso_shared_int *shared_int = urb->context; | |
9390 | + struct hso_serial *serial; | |
9391 | + unsigned char *port_req; | |
9392 | + int status = urb->status; | |
9393 | + int i; | |
9394 | + | |
9395 | + usb_mark_last_busy(urb->dev); | |
9396 | + | |
9397 | + /* sanity check */ | |
9398 | + if (!shared_int) | |
9399 | + return; | |
9400 | + | |
9401 | + /* status check */ | |
9402 | + if (status) { | |
9403 | + handle_usb_error(status, __func__, NULL); | |
9404 | + return; | |
9405 | + } | |
9406 | + D4("\n--- Got intr callback 0x%02X ---", status); | |
9407 | + | |
9408 | + /* what request? */ | |
9409 | + port_req = urb->transfer_buffer; | |
9410 | + D4(" port_req = 0x%.2X\n", *port_req); | |
9411 | + /* loop over all muxed ports to find the one sending this */ | |
9412 | + for (i = 0; i < 8; i++) { | |
9413 | + /* max 8 channels on MUX */ | |
9414 | + if (*port_req & (1 << i)) { | |
9415 | + serial = get_serial_by_shared_int_and_type(shared_int, | |
9416 | + (1 << i)); | |
9417 | + if (serial != NULL) { | |
9418 | + D1("Pending read interrupt on port %d\n", i); | |
9419 | + spin_lock(&serial->serial_lock); | |
9420 | + if (serial->rx_state == RX_IDLE && | |
9421 | + atomic_read(&serial->port.count) > 0) { | |
9422 | + /* Setup and send a ctrl req read on | |
9423 | + * port i */ | |
9424 | + if (!serial->rx_urb_filled[0]) { | |
9425 | + serial->rx_state = RX_SENT; | |
9426 | + hso_mux_serial_read(serial); | |
9427 | + } else | |
9428 | + serial->rx_state = RX_PENDING; | |
9429 | + } else { | |
9430 | + D1("Already a read pending on " | |
9431 | + "port %d or port not open\n", i); | |
9432 | + } | |
9433 | + spin_unlock(&serial->serial_lock); | |
9434 | + } | |
9435 | + } | |
9436 | + } | |
9437 | + /* Resubmit interrupt urb */ | |
9438 | + hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC); | |
9439 | +} | |
9440 | + | |
9441 | +/* called for writing to muxed serial port */ | |
9442 | +static int hso_mux_serial_write_data(struct hso_serial *serial) | |
9443 | +{ | |
9444 | + if (NULL == serial) | |
9445 | + return -EINVAL; | |
9446 | + | |
9447 | + return mux_device_request(serial, | |
9448 | + USB_CDC_SEND_ENCAPSULATED_COMMAND, | |
9449 | + serial->parent->port_spec & HSO_PORT_MASK, | |
9450 | + serial->tx_urb, | |
9451 | + &serial->ctrl_req_tx, | |
9452 | + serial->tx_data, serial->tx_data_count); | |
9453 | +} | |
9454 | + | |
9455 | +/* write callback for Diag and CS port */ | |
9456 | +static void hso_std_serial_write_bulk_callback(struct urb *urb) | |
9457 | +{ | |
9458 | + struct hso_serial *serial = urb->context; | |
9459 | + int status = urb->status; | |
9460 | + | |
9461 | + /* sanity check */ | |
9462 | + if (!serial) { | |
9463 | + D1("serial == NULL"); | |
9464 | + return; | |
9465 | + } | |
9466 | + | |
9467 | + spin_lock(&serial->serial_lock); | |
9468 | + serial->tx_urb_used = 0; | |
9469 | + spin_unlock(&serial->serial_lock); | |
9470 | + if (status) { | |
9471 | + handle_usb_error(status, __func__, serial->parent); | |
9472 | + return; | |
9473 | + } | |
9474 | + hso_put_activity(serial->parent); | |
9475 | + tty_port_tty_wakeup(&serial->port); | |
9476 | + hso_kick_transmit(serial); | |
9477 | + | |
9478 | + D1(" "); | |
9479 | +} | |
9480 | + | |
9481 | +/* called for writing diag or CS serial port */ | |
9482 | +static int hso_std_serial_write_data(struct hso_serial *serial) | |
9483 | +{ | |
9484 | + int count = serial->tx_data_count; | |
9485 | + int result; | |
9486 | + | |
9487 | + usb_fill_bulk_urb(serial->tx_urb, | |
9488 | + serial->parent->usb, | |
9489 | + usb_sndbulkpipe(serial->parent->usb, | |
9490 | + serial->out_endp-> | |
9491 | + bEndpointAddress & 0x7F), | |
9492 | + serial->tx_data, serial->tx_data_count, | |
9493 | + hso_std_serial_write_bulk_callback, serial); | |
9494 | + | |
9495 | + result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC); | |
9496 | + if (result) { | |
9497 | + dev_warn(&serial->parent->usb->dev, | |
9498 | + "Failed to submit urb - res %d\n", result); | |
9499 | + return result; | |
9500 | + } | |
9501 | + | |
9502 | + return count; | |
9503 | +} | |
9504 | + | |
9505 | +/* callback after read or write on muxed serial port */ | |
9506 | +static void ctrl_callback(struct urb *urb) | |
9507 | +{ | |
9508 | + struct hso_serial *serial = urb->context; | |
9509 | + struct usb_ctrlrequest *req; | |
9510 | + int status = urb->status; | |
9511 | + | |
9512 | + /* sanity check */ | |
9513 | + if (!serial) | |
9514 | + return; | |
9515 | + | |
9516 | + spin_lock(&serial->serial_lock); | |
9517 | + serial->tx_urb_used = 0; | |
9518 | + spin_unlock(&serial->serial_lock); | |
9519 | + if (status) { | |
9520 | + handle_usb_error(status, __func__, serial->parent); | |
9521 | + return; | |
9522 | + } | |
9523 | + | |
9524 | + /* what request? */ | |
9525 | + req = (struct usb_ctrlrequest *)(urb->setup_packet); | |
9526 | + D4("\n--- Got muxed ctrl callback 0x%02X ---", status); | |
9527 | + D4("Actual length of urb = %d\n", urb->actual_length); | |
9528 | + DUMP1(urb->transfer_buffer, urb->actual_length); | |
9529 | + | |
9530 | + if (req->bRequestType == | |
9531 | + (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { | |
9532 | + /* response to a read command */ | |
9533 | + serial->rx_urb_filled[0] = 1; | |
9534 | + spin_lock(&serial->serial_lock); | |
9535 | + put_rxbuf_data_and_resubmit_ctrl_urb(serial); | |
9536 | + spin_unlock(&serial->serial_lock); | |
9537 | + } else { | |
9538 | + hso_put_activity(serial->parent); | |
9539 | + tty_port_tty_wakeup(&serial->port); | |
9540 | + /* response to a write command */ | |
9541 | + hso_kick_transmit(serial); | |
9542 | + } | |
9543 | +} | |
9544 | + | |
9545 | +/* handle RX data for serial port */ | |
9546 | +static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) | |
9547 | +{ | |
9548 | + struct tty_struct *tty; | |
9549 | + int count; | |
9550 | + | |
9551 | + /* Sanity check */ | |
9552 | + if (urb == NULL || serial == NULL) { | |
9553 | + D1("serial = NULL"); | |
9554 | + return -2; | |
9555 | + } | |
9556 | + | |
9557 | + tty = tty_port_tty_get(&serial->port); | |
9558 | + | |
9559 | + if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { | |
9560 | + tty_kref_put(tty); | |
9561 | + return -1; | |
9562 | + } | |
9563 | + | |
9564 | + /* Push data to tty */ | |
9565 | + D1("data to push to tty"); | |
9566 | + count = tty_buffer_request_room(&serial->port, urb->actual_length); | |
9567 | + if (count >= urb->actual_length) { | |
9568 | + tty_insert_flip_string(&serial->port, urb->transfer_buffer, | |
9569 | + urb->actual_length); | |
9570 | + tty_flip_buffer_push(&serial->port); | |
9571 | + } else { | |
9572 | + dev_warn(&serial->parent->usb->dev, | |
9573 | + "dropping data, %d bytes lost\n", urb->actual_length); | |
9574 | + } | |
9575 | + | |
9576 | + tty_kref_put(tty); | |
9577 | + | |
9578 | + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; | |
9579 | + | |
9580 | + return 0; | |
9581 | +} | |
9582 | + | |
9583 | + | |
9584 | +/* Base driver functions */ | |
9585 | + | |
9586 | +static void hso_log_port(struct hso_device *hso_dev) | |
9587 | +{ | |
9588 | + char *port_type; | |
9589 | + char port_dev[20]; | |
9590 | + | |
9591 | + switch (hso_dev->port_spec & HSO_PORT_MASK) { | |
9592 | + case HSO_PORT_CONTROL: | |
9593 | + port_type = "Control"; | |
9594 | + break; | |
9595 | + case HSO_PORT_APP: | |
9596 | + port_type = "Application"; | |
9597 | + break; | |
9598 | + case HSO_PORT_GPS: | |
9599 | + port_type = "GPS"; | |
9600 | + break; | |
9601 | + case HSO_PORT_GPS_CONTROL: | |
9602 | + port_type = "GPS control"; | |
9603 | + break; | |
9604 | + case HSO_PORT_APP2: | |
9605 | + port_type = "Application2"; | |
9606 | + break; | |
9607 | + case HSO_PORT_PCSC: | |
9608 | + port_type = "PCSC"; | |
9609 | + break; | |
9610 | + case HSO_PORT_DIAG: | |
9611 | + port_type = "Diagnostic"; | |
9612 | + break; | |
9613 | + case HSO_PORT_DIAG2: | |
9614 | + port_type = "Diagnostic2"; | |
9615 | + break; | |
9616 | + case HSO_PORT_MODEM: | |
9617 | + port_type = "Modem"; | |
9618 | + break; | |
9619 | + case HSO_PORT_NETWORK: | |
9620 | + port_type = "Network"; | |
9621 | + break; | |
9622 | + default: | |
9623 | + port_type = "Unknown"; | |
9624 | + break; | |
9625 | + } | |
9626 | + if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { | |
9627 | + sprintf(port_dev, "%s", dev2net(hso_dev)->net->name); | |
9628 | + } else | |
9629 | + sprintf(port_dev, "/dev/%s%d", tty_filename, | |
9630 | + dev2ser(hso_dev)->minor); | |
9631 | + | |
9632 | + dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n", | |
9633 | + port_type, port_dev); | |
9634 | +} | |
9635 | + | |
9636 | +static int hso_start_net_device(struct hso_device *hso_dev) | |
9637 | +{ | |
9638 | + int i, result = 0; | |
9639 | + struct hso_net *hso_net = dev2net(hso_dev); | |
9640 | + | |
9641 | + if (!hso_net) | |
9642 | + return -ENODEV; | |
9643 | + | |
9644 | + /* send URBs for all read buffers */ | |
9645 | + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { | |
9646 | + | |
9647 | + /* Prep a receive URB */ | |
9648 | + usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i], | |
9649 | + hso_dev->usb, | |
9650 | + usb_rcvbulkpipe(hso_dev->usb, | |
9651 | + hso_net->in_endp-> | |
9652 | + bEndpointAddress & 0x7F), | |
9653 | + hso_net->mux_bulk_rx_buf_pool[i], | |
9654 | + MUX_BULK_RX_BUF_SIZE, read_bulk_callback, | |
9655 | + hso_net); | |
9656 | + | |
9657 | + /* Put it out there so the device can send us stuff */ | |
9658 | + result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i], | |
9659 | + GFP_NOIO); | |
9660 | + if (result) | |
9661 | + dev_warn(&hso_dev->usb->dev, | |
9662 | + "%s failed mux_bulk_rx_urb[%d] %d\n", __func__, | |
9663 | + i, result); | |
9664 | + } | |
9665 | + | |
9666 | + return result; | |
9667 | +} | |
9668 | + | |
9669 | +static int hso_stop_net_device(struct hso_device *hso_dev) | |
9670 | +{ | |
9671 | + int i; | |
9672 | + struct hso_net *hso_net = dev2net(hso_dev); | |
9673 | + | |
9674 | + if (!hso_net) | |
9675 | + return -ENODEV; | |
9676 | + | |
9677 | + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { | |
9678 | + if (hso_net->mux_bulk_rx_urb_pool[i]) | |
9679 | + usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]); | |
9680 | + | |
9681 | + } | |
9682 | + if (hso_net->mux_bulk_tx_urb) | |
9683 | + usb_kill_urb(hso_net->mux_bulk_tx_urb); | |
9684 | + | |
9685 | + return 0; | |
9686 | +} | |
9687 | + | |
9688 | +static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) | |
9689 | +{ | |
9690 | + int i, result = 0; | |
9691 | + struct hso_serial *serial = dev2ser(hso_dev); | |
9692 | + | |
9693 | + if (!serial) | |
9694 | + return -ENODEV; | |
9695 | + | |
9696 | + /* If it is not the MUX port fill in and submit a bulk urb (already | |
9697 | + * allocated in hso_serial_start) */ | |
9698 | + if (!(serial->parent->port_spec & HSO_INTF_MUX)) { | |
9699 | + for (i = 0; i < serial->num_rx_urbs; i++) { | |
9700 | + usb_fill_bulk_urb(serial->rx_urb[i], | |
9701 | + serial->parent->usb, | |
9702 | + usb_rcvbulkpipe(serial->parent->usb, | |
9703 | + serial->in_endp-> | |
9704 | + bEndpointAddress & | |
9705 | + 0x7F), | |
9706 | + serial->rx_data[i], | |
9707 | + serial->rx_data_length, | |
9708 | + hso_std_serial_read_bulk_callback, | |
9709 | + serial); | |
9710 | + result = usb_submit_urb(serial->rx_urb[i], flags); | |
9711 | + if (result) { | |
9712 | + dev_warn(&serial->parent->usb->dev, | |
9713 | + "Failed to submit urb - res %d\n", | |
9714 | + result); | |
9715 | + break; | |
9716 | + } | |
9717 | + } | |
9718 | + } else { | |
9719 | + mutex_lock(&serial->shared_int->shared_int_lock); | |
9720 | + if (!serial->shared_int->use_count) { | |
9721 | + result = | |
9722 | + hso_mux_submit_intr_urb(serial->shared_int, | |
9723 | + hso_dev->usb, flags); | |
9724 | + } | |
9725 | + serial->shared_int->use_count++; | |
9726 | + mutex_unlock(&serial->shared_int->shared_int_lock); | |
9727 | + } | |
9728 | + if (serial->tiocmget) | |
9729 | + tiocmget_submit_urb(serial, | |
9730 | + serial->tiocmget, | |
9731 | + serial->parent->usb); | |
9732 | + return result; | |
9733 | +} | |
9734 | + | |
9735 | +static int hso_stop_serial_device(struct hso_device *hso_dev) | |
9736 | +{ | |
9737 | + int i; | |
9738 | + struct hso_serial *serial = dev2ser(hso_dev); | |
9739 | + struct hso_tiocmget *tiocmget; | |
9740 | + | |
9741 | + if (!serial) | |
9742 | + return -ENODEV; | |
9743 | + | |
9744 | + for (i = 0; i < serial->num_rx_urbs; i++) { | |
9745 | + if (serial->rx_urb[i]) { | |
9746 | + usb_kill_urb(serial->rx_urb[i]); | |
9747 | + serial->rx_urb_filled[i] = 0; | |
9748 | + } | |
9749 | + } | |
9750 | + serial->curr_rx_urb_idx = 0; | |
9751 | + | |
9752 | + if (serial->tx_urb) | |
9753 | + usb_kill_urb(serial->tx_urb); | |
9754 | + | |
9755 | + if (serial->shared_int) { | |
9756 | + mutex_lock(&serial->shared_int->shared_int_lock); | |
9757 | + if (serial->shared_int->use_count && | |
9758 | + (--serial->shared_int->use_count == 0)) { | |
9759 | + struct urb *urb; | |
9760 | + | |
9761 | + urb = serial->shared_int->shared_intr_urb; | |
9762 | + if (urb) | |
9763 | + usb_kill_urb(urb); | |
9764 | + } | |
9765 | + mutex_unlock(&serial->shared_int->shared_int_lock); | |
9766 | + } | |
9767 | + tiocmget = serial->tiocmget; | |
9768 | + if (tiocmget) { | |
9769 | + wake_up_interruptible(&tiocmget->waitq); | |
9770 | + usb_kill_urb(tiocmget->urb); | |
9771 | + } | |
9772 | + | |
9773 | + return 0; | |
9774 | +} | |
9775 | + | |
9776 | +static void hso_serial_common_free(struct hso_serial *serial) | |
9777 | +{ | |
9778 | + int i; | |
9779 | + | |
9780 | + if (serial->parent->dev) | |
9781 | + device_remove_file(serial->parent->dev, &dev_attr_hsotype); | |
9782 | + | |
9783 | + tty_unregister_device(tty_drv, serial->minor); | |
9784 | + | |
9785 | + for (i = 0; i < serial->num_rx_urbs; i++) { | |
9786 | + /* unlink and free RX URB */ | |
9787 | + usb_free_urb(serial->rx_urb[i]); | |
9788 | + /* free the RX buffer */ | |
9789 | + kfree(serial->rx_data[i]); | |
9790 | + } | |
9791 | + | |
9792 | + /* unlink and free TX URB */ | |
9793 | + usb_free_urb(serial->tx_urb); | |
9794 | + kfree(serial->tx_data); | |
9795 | + tty_port_destroy(&serial->port); | |
9796 | +} | |
9797 | + | |
9798 | +static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, | |
9799 | + int rx_size, int tx_size) | |
9800 | +{ | |
9801 | + struct device *dev; | |
9802 | + int minor; | |
9803 | + int i; | |
9804 | + | |
9805 | + tty_port_init(&serial->port); | |
9806 | + | |
9807 | + minor = get_free_serial_index(); | |
9808 | + if (minor < 0) | |
9809 | + goto exit; | |
9810 | + | |
9811 | + /* register our minor number */ | |
9812 | + serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, | |
9813 | + minor, &serial->parent->interface->dev); | |
9814 | + dev = serial->parent->dev; | |
9815 | + dev_set_drvdata(dev, serial->parent); | |
9816 | + i = device_create_file(dev, &dev_attr_hsotype); | |
9817 | + | |
9818 | + /* fill in specific data for later use */ | |
9819 | + serial->minor = minor; | |
9820 | + serial->magic = HSO_SERIAL_MAGIC; | |
9821 | + spin_lock_init(&serial->serial_lock); | |
9822 | + serial->num_rx_urbs = num_urbs; | |
9823 | + | |
9824 | + /* RX, allocate urb and initialize */ | |
9825 | + | |
9826 | + /* prepare our RX buffer */ | |
9827 | + serial->rx_data_length = rx_size; | |
9828 | + for (i = 0; i < serial->num_rx_urbs; i++) { | |
9829 | + serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); | |
9830 | + if (!serial->rx_urb[i]) { | |
9831 | + dev_err(dev, "Could not allocate urb?\n"); | |
9832 | + goto exit; | |
9833 | + } | |
9834 | + serial->rx_urb[i]->transfer_buffer = NULL; | |
9835 | + serial->rx_urb[i]->transfer_buffer_length = 0; | |
9836 | + serial->rx_data[i] = kzalloc(serial->rx_data_length, | |
9837 | + GFP_KERNEL); | |
9838 | + if (!serial->rx_data[i]) | |
9839 | + goto exit; | |
9840 | + } | |
9841 | + | |
9842 | + /* TX, allocate urb and initialize */ | |
9843 | + serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
9844 | + if (!serial->tx_urb) { | |
9845 | + dev_err(dev, "Could not allocate urb?\n"); | |
9846 | + goto exit; | |
9847 | + } | |
9848 | + serial->tx_urb->transfer_buffer = NULL; | |
9849 | + serial->tx_urb->transfer_buffer_length = 0; | |
9850 | + /* prepare our TX buffer */ | |
9851 | + serial->tx_data_count = 0; | |
9852 | + serial->tx_buffer_count = 0; | |
9853 | + serial->tx_data_length = tx_size; | |
9854 | + serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL); | |
9855 | + if (!serial->tx_data) | |
9856 | + goto exit; | |
9857 | + | |
9858 | + serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL); | |
9859 | + if (!serial->tx_buffer) | |
9860 | + goto exit; | |
9861 | + | |
9862 | + return 0; | |
9863 | +exit: | |
9864 | + hso_serial_common_free(serial); | |
9865 | + return -1; | |
9866 | +} | |
9867 | + | |
9868 | +/* Creates a general hso device */ | |
9869 | +static struct hso_device *hso_create_device(struct usb_interface *intf, | |
9870 | + int port_spec) | |
9871 | +{ | |
9872 | + struct hso_device *hso_dev; | |
9873 | + | |
9874 | + hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC); | |
9875 | + if (!hso_dev) | |
9876 | + return NULL; | |
9877 | + | |
9878 | + hso_dev->port_spec = port_spec; | |
9879 | + hso_dev->usb = interface_to_usbdev(intf); | |
9880 | + hso_dev->interface = intf; | |
9881 | + kref_init(&hso_dev->ref); | |
9882 | + mutex_init(&hso_dev->mutex); | |
9883 | + | |
9884 | + INIT_WORK(&hso_dev->async_get_intf, async_get_intf); | |
9885 | + INIT_WORK(&hso_dev->async_put_intf, async_put_intf); | |
9886 | + INIT_WORK(&hso_dev->reset_device, reset_device); | |
9887 | + | |
9888 | + return hso_dev; | |
9889 | +} | |
9890 | + | |
9891 | +/* Removes a network device in the network device table */ | |
9892 | +static int remove_net_device(struct hso_device *hso_dev) | |
9893 | +{ | |
9894 | + int i; | |
9895 | + | |
9896 | + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { | |
9897 | + if (network_table[i] == hso_dev) { | |
9898 | + network_table[i] = NULL; | |
9899 | + break; | |
9900 | + } | |
9901 | + } | |
9902 | + if (i == HSO_MAX_NET_DEVICES) | |
9903 | + return -1; | |
9904 | + return 0; | |
9905 | +} | |
9906 | + | |
9907 | +/* Frees our network device */ | |
9908 | +static void hso_free_net_device(struct hso_device *hso_dev) | |
9909 | +{ | |
9910 | + int i; | |
9911 | + struct hso_net *hso_net = dev2net(hso_dev); | |
9912 | + | |
9913 | + if (!hso_net) | |
9914 | + return; | |
9915 | + | |
9916 | + remove_net_device(hso_net->parent); | |
9917 | + | |
9918 | + if (hso_net->net) | |
9919 | + unregister_netdev(hso_net->net); | |
9920 | + | |
9921 | + /* start freeing */ | |
9922 | + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { | |
9923 | + usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); | |
9924 | + kfree(hso_net->mux_bulk_rx_buf_pool[i]); | |
9925 | + hso_net->mux_bulk_rx_buf_pool[i] = NULL; | |
9926 | + } | |
9927 | + usb_free_urb(hso_net->mux_bulk_tx_urb); | |
9928 | + kfree(hso_net->mux_bulk_tx_buf); | |
9929 | + hso_net->mux_bulk_tx_buf = NULL; | |
9930 | + | |
9931 | + if (hso_net->net) | |
9932 | + free_netdev(hso_net->net); | |
9933 | + | |
9934 | + kfree(hso_dev); | |
9935 | +} | |
9936 | + | |
9937 | +static const struct net_device_ops hso_netdev_ops = { | |
9938 | + .ndo_open = hso_net_open, | |
9939 | + .ndo_stop = hso_net_close, | |
9940 | + .ndo_start_xmit = hso_net_start_xmit, | |
9941 | + .ndo_tx_timeout = hso_net_tx_timeout, | |
9942 | +}; | |
9943 | + | |
9944 | +/* initialize the network interface */ | |
9945 | +static void hso_net_init(struct net_device *net) | |
9946 | +{ | |
9947 | + struct hso_net *hso_net = netdev_priv(net); | |
9948 | + | |
9949 | + D1("sizeof hso_net is %d", (int)sizeof(*hso_net)); | |
9950 | + | |
9951 | + /* fill in the other fields */ | |
9952 | + net->netdev_ops = &hso_netdev_ops; | |
9953 | + net->watchdog_timeo = HSO_NET_TX_TIMEOUT; | |
9954 | + net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; | |
9955 | + net->type = ARPHRD_NONE; | |
9956 | + net->mtu = DEFAULT_MTU - 14; | |
9957 | + net->tx_queue_len = 10; | |
9958 | + net->ethtool_ops = &ops; | |
9959 | + | |
9960 | + /* and initialize the semaphore */ | |
9961 | + spin_lock_init(&hso_net->net_lock); | |
9962 | +} | |
9963 | + | |
9964 | +/* Adds a network device in the network device table */ | |
9965 | +static int add_net_device(struct hso_device *hso_dev) | |
9966 | +{ | |
9967 | + int i; | |
9968 | + | |
9969 | + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { | |
9970 | + if (network_table[i] == NULL) { | |
9971 | + network_table[i] = hso_dev; | |
9972 | + break; | |
9973 | + } | |
9974 | + } | |
9975 | + if (i == HSO_MAX_NET_DEVICES) | |
9976 | + return -1; | |
9977 | + return 0; | |
9978 | +} | |
9979 | + | |
9980 | +static int hso_rfkill_set_block(void *data, bool blocked) | |
9981 | +{ | |
9982 | + struct hso_device *hso_dev = data; | |
9983 | + int enabled = !blocked; | |
9984 | + int rv; | |
9985 | + | |
9986 | + mutex_lock(&hso_dev->mutex); | |
9987 | + if (hso_dev->usb_gone) | |
9988 | + rv = 0; | |
9989 | + else | |
9990 | + rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), | |
9991 | + enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, | |
9992 | + USB_CTRL_SET_TIMEOUT); | |
9993 | + mutex_unlock(&hso_dev->mutex); | |
9994 | + return rv; | |
9995 | +} | |
9996 | + | |
9997 | +static const struct rfkill_ops hso_rfkill_ops = { | |
9998 | + .set_block = hso_rfkill_set_block, | |
9999 | +}; | |
10000 | + | |
10001 | +/* Creates and sets up everything for rfkill */ | |
10002 | +static void hso_create_rfkill(struct hso_device *hso_dev, | |
10003 | + struct usb_interface *interface) | |
10004 | +{ | |
10005 | + struct hso_net *hso_net = dev2net(hso_dev); | |
10006 | + struct device *dev = &hso_net->net->dev; | |
10007 | + char *rfkn; | |
10008 | + | |
10009 | + rfkn = kzalloc(20, GFP_KERNEL); | |
10010 | + if (!rfkn) | |
10011 | + dev_err(dev, "%s - Out of memory\n", __func__); | |
10012 | + | |
10013 | + snprintf(rfkn, 20, "hso-%d", | |
10014 | + interface->altsetting->desc.bInterfaceNumber); | |
10015 | + | |
10016 | + hso_net->rfkill = rfkill_alloc(rfkn, | |
10017 | + &interface_to_usbdev(interface)->dev, | |
10018 | + RFKILL_TYPE_WWAN, | |
10019 | + &hso_rfkill_ops, hso_dev); | |
10020 | + if (!hso_net->rfkill) { | |
10021 | + dev_err(dev, "%s - Out of memory\n", __func__); | |
10022 | + kfree(rfkn); | |
10023 | + return; | |
10024 | + } | |
10025 | + if (rfkill_register(hso_net->rfkill) < 0) { | |
10026 | + rfkill_destroy(hso_net->rfkill); | |
10027 | + kfree(rfkn); | |
10028 | + hso_net->rfkill = NULL; | |
10029 | + dev_err(dev, "%s - Failed to register rfkill\n", __func__); | |
10030 | + return; | |
10031 | + } | |
10032 | +} | |
10033 | + | |
10034 | +static struct device_type hso_type = { | |
10035 | + .name = "wwan", | |
10036 | +}; | |
10037 | + | |
10038 | +/* Creates our network device */ | |
10039 | +static struct hso_device *hso_create_net_device(struct usb_interface *interface, | |
10040 | + int port_spec) | |
10041 | +{ | |
10042 | + int result, i; | |
10043 | + struct net_device *net; | |
10044 | + struct hso_net *hso_net; | |
10045 | + struct hso_device *hso_dev; | |
10046 | + | |
10047 | + hso_dev = hso_create_device(interface, port_spec); | |
10048 | + if (!hso_dev) | |
10049 | + return NULL; | |
10050 | + | |
10051 | + /* allocate our network device, then we can put in our private data */ | |
10052 | + /* call hso_net_init to do the basic initialization */ | |
10053 | + net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN, | |
10054 | + hso_net_init); | |
10055 | + if (!net) { | |
10056 | + dev_err(&interface->dev, "Unable to create ethernet device\n"); | |
10057 | + goto exit; | |
10058 | + } | |
10059 | + | |
10060 | + hso_net = netdev_priv(net); | |
10061 | + | |
10062 | + hso_dev->port_data.dev_net = hso_net; | |
10063 | + hso_net->net = net; | |
10064 | + hso_net->parent = hso_dev; | |
10065 | + | |
10066 | + hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, | |
10067 | + USB_DIR_IN); | |
10068 | + if (!hso_net->in_endp) { | |
10069 | + dev_err(&interface->dev, "Can't find BULK IN endpoint\n"); | |
10070 | + goto exit; | |
10071 | + } | |
10072 | + hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, | |
10073 | + USB_DIR_OUT); | |
10074 | + if (!hso_net->out_endp) { | |
10075 | + dev_err(&interface->dev, "Can't find BULK OUT endpoint\n"); | |
10076 | + goto exit; | |
10077 | + } | |
10078 | + SET_NETDEV_DEV(net, &interface->dev); | |
10079 | + SET_NETDEV_DEVTYPE(net, &hso_type); | |
10080 | + | |
10081 | + /* registering our net device */ | |
10082 | + result = register_netdev(net); | |
10083 | + if (result) { | |
10084 | + dev_err(&interface->dev, "Failed to register device\n"); | |
10085 | + goto exit; | |
10086 | + } | |
10087 | + | |
10088 | + /* start allocating */ | |
10089 | + for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { | |
10090 | + hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL); | |
10091 | + if (!hso_net->mux_bulk_rx_urb_pool[i]) { | |
10092 | + dev_err(&interface->dev, "Could not allocate rx urb\n"); | |
10093 | + goto exit; | |
10094 | + } | |
10095 | + hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE, | |
10096 | + GFP_KERNEL); | |
10097 | + if (!hso_net->mux_bulk_rx_buf_pool[i]) | |
10098 | + goto exit; | |
10099 | + } | |
10100 | + hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
10101 | + if (!hso_net->mux_bulk_tx_urb) { | |
10102 | + dev_err(&interface->dev, "Could not allocate tx urb\n"); | |
10103 | + goto exit; | |
10104 | + } | |
10105 | + hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL); | |
10106 | + if (!hso_net->mux_bulk_tx_buf) | |
10107 | + goto exit; | |
10108 | + | |
10109 | + add_net_device(hso_dev); | |
10110 | + | |
10111 | + hso_log_port(hso_dev); | |
10112 | + | |
10113 | + hso_create_rfkill(hso_dev, interface); | |
10114 | + | |
10115 | + return hso_dev; | |
10116 | +exit: | |
10117 | + hso_free_net_device(hso_dev); | |
10118 | + return NULL; | |
10119 | +} | |
10120 | + | |
10121 | +static void hso_free_tiomget(struct hso_serial *serial) | |
10122 | +{ | |
10123 | + struct hso_tiocmget *tiocmget; | |
10124 | + if (!serial) | |
10125 | + return; | |
10126 | + tiocmget = serial->tiocmget; | |
10127 | + if (tiocmget) { | |
10128 | + usb_free_urb(tiocmget->urb); | |
10129 | + tiocmget->urb = NULL; | |
10130 | + serial->tiocmget = NULL; | |
10131 | + kfree(tiocmget); | |
10132 | + } | |
10133 | +} | |
10134 | + | |
10135 | +/* Frees an AT channel ( goes for both mux and non-mux ) */ | |
10136 | +static void hso_free_serial_device(struct hso_device *hso_dev) | |
10137 | +{ | |
10138 | + struct hso_serial *serial = dev2ser(hso_dev); | |
10139 | + | |
10140 | + if (!serial) | |
10141 | + return; | |
10142 | + set_serial_by_index(serial->minor, NULL); | |
10143 | + | |
10144 | + hso_serial_common_free(serial); | |
10145 | + | |
10146 | + if (serial->shared_int) { | |
10147 | + mutex_lock(&serial->shared_int->shared_int_lock); | |
10148 | + if (--serial->shared_int->ref_count == 0) | |
10149 | + hso_free_shared_int(serial->shared_int); | |
10150 | + else | |
10151 | + mutex_unlock(&serial->shared_int->shared_int_lock); | |
10152 | + } | |
10153 | + hso_free_tiomget(serial); | |
10154 | + kfree(serial); | |
10155 | + kfree(hso_dev); | |
10156 | +} | |
10157 | + | |
10158 | +/* Creates a bulk AT channel */ | |
10159 | +static struct hso_device *hso_create_bulk_serial_device( | |
10160 | + struct usb_interface *interface, int port) | |
10161 | +{ | |
10162 | + struct hso_device *hso_dev; | |
10163 | + struct hso_serial *serial; | |
10164 | + int num_urbs; | |
10165 | + struct hso_tiocmget *tiocmget; | |
10166 | + | |
10167 | + hso_dev = hso_create_device(interface, port); | |
10168 | + if (!hso_dev) | |
10169 | + return NULL; | |
10170 | + | |
10171 | + serial = kzalloc(sizeof(*serial), GFP_KERNEL); | |
10172 | + if (!serial) | |
10173 | + goto exit; | |
10174 | + | |
10175 | + serial->parent = hso_dev; | |
10176 | + hso_dev->port_data.dev_serial = serial; | |
10177 | + | |
10178 | + if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { | |
10179 | + num_urbs = 2; | |
10180 | + serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), | |
10181 | + GFP_KERNEL); | |
10182 | + /* it isn't going to break our heart if serial->tiocmget | |
10183 | + * allocation fails don't bother checking this. | |
10184 | + */ | |
10185 | + if (serial->tiocmget) { | |
10186 | + tiocmget = serial->tiocmget; | |
10187 | + tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); | |
10188 | + if (tiocmget->urb) { | |
10189 | + mutex_init(&tiocmget->mutex); | |
10190 | + init_waitqueue_head(&tiocmget->waitq); | |
10191 | + tiocmget->endp = hso_get_ep( | |
10192 | + interface, | |
10193 | + USB_ENDPOINT_XFER_INT, | |
10194 | + USB_DIR_IN); | |
10195 | + } else | |
10196 | + hso_free_tiomget(serial); | |
10197 | + } | |
10198 | + } | |
10199 | + else | |
10200 | + num_urbs = 1; | |
10201 | + | |
10202 | + if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE, | |
10203 | + BULK_URB_TX_SIZE)) | |
10204 | + goto exit; | |
10205 | + | |
10206 | + serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, | |
10207 | + USB_DIR_IN); | |
10208 | + if (!serial->in_endp) { | |
10209 | + dev_err(&interface->dev, "Failed to find BULK IN ep\n"); | |
10210 | + goto exit2; | |
10211 | + } | |
10212 | + | |
10213 | + if (! | |
10214 | + (serial->out_endp = | |
10215 | + hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { | |
10216 | + dev_err(&interface->dev, "Failed to find BULK IN ep\n"); | |
10217 | + goto exit2; | |
10218 | + } | |
10219 | + | |
10220 | + serial->write_data = hso_std_serial_write_data; | |
10221 | + | |
10222 | + /* and record this serial */ | |
10223 | + set_serial_by_index(serial->minor, serial); | |
10224 | + | |
10225 | + /* setup the proc dirs and files if needed */ | |
10226 | + hso_log_port(hso_dev); | |
10227 | + | |
10228 | + /* done, return it */ | |
10229 | + return hso_dev; | |
10230 | + | |
10231 | +exit2: | |
10232 | + hso_serial_common_free(serial); | |
10233 | +exit: | |
10234 | + hso_free_tiomget(serial); | |
10235 | + kfree(serial); | |
10236 | + kfree(hso_dev); | |
10237 | + return NULL; | |
10238 | +} | |
10239 | + | |
10240 | +/* Creates a multiplexed AT channel */ | |
10241 | +static | |
10242 | +struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface, | |
10243 | + int port, | |
10244 | + struct hso_shared_int *mux) | |
10245 | +{ | |
10246 | + struct hso_device *hso_dev; | |
10247 | + struct hso_serial *serial; | |
10248 | + int port_spec; | |
10249 | + | |
10250 | + port_spec = HSO_INTF_MUX; | |
10251 | + port_spec &= ~HSO_PORT_MASK; | |
10252 | + | |
10253 | + port_spec |= hso_mux_to_port(port); | |
10254 | + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT) | |
10255 | + return NULL; | |
10256 | + | |
10257 | + hso_dev = hso_create_device(interface, port_spec); | |
10258 | + if (!hso_dev) | |
10259 | + return NULL; | |
10260 | + | |
10261 | + serial = kzalloc(sizeof(*serial), GFP_KERNEL); | |
10262 | + if (!serial) | |
10263 | + goto exit; | |
10264 | + | |
10265 | + hso_dev->port_data.dev_serial = serial; | |
10266 | + serial->parent = hso_dev; | |
10267 | + | |
10268 | + if (hso_serial_common_create | |
10269 | + (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE)) | |
10270 | + goto exit; | |
10271 | + | |
10272 | + serial->tx_data_length--; | |
10273 | + serial->write_data = hso_mux_serial_write_data; | |
10274 | + | |
10275 | + serial->shared_int = mux; | |
10276 | + mutex_lock(&serial->shared_int->shared_int_lock); | |
10277 | + serial->shared_int->ref_count++; | |
10278 | + mutex_unlock(&serial->shared_int->shared_int_lock); | |
10279 | + | |
10280 | + /* and record this serial */ | |
10281 | + set_serial_by_index(serial->minor, serial); | |
10282 | + | |
10283 | + /* setup the proc dirs and files if needed */ | |
10284 | + hso_log_port(hso_dev); | |
10285 | + | |
10286 | + /* done, return it */ | |
10287 | + return hso_dev; | |
10288 | + | |
10289 | +exit: | |
10290 | + if (serial) { | |
10291 | + tty_unregister_device(tty_drv, serial->minor); | |
10292 | + kfree(serial); | |
10293 | + } | |
10294 | + if (hso_dev) | |
10295 | + kfree(hso_dev); | |
10296 | + return NULL; | |
10297 | + | |
10298 | +} | |
10299 | + | |
10300 | +static void hso_free_shared_int(struct hso_shared_int *mux) | |
10301 | +{ | |
10302 | + usb_free_urb(mux->shared_intr_urb); | |
10303 | + kfree(mux->shared_intr_buf); | |
10304 | + mutex_unlock(&mux->shared_int_lock); | |
10305 | + kfree(mux); | |
10306 | +} | |
10307 | + | |
10308 | +static | |
10309 | +struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface) | |
10310 | +{ | |
10311 | + struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL); | |
10312 | + | |
10313 | + if (!mux) | |
10314 | + return NULL; | |
10315 | + | |
10316 | + mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, | |
10317 | + USB_DIR_IN); | |
10318 | + if (!mux->intr_endp) { | |
10319 | + dev_err(&interface->dev, "Can't find INT IN endpoint\n"); | |
10320 | + goto exit; | |
10321 | + } | |
10322 | + | |
10323 | + mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL); | |
10324 | + if (!mux->shared_intr_urb) { | |
10325 | + dev_err(&interface->dev, "Could not allocate intr urb?\n"); | |
10326 | + goto exit; | |
10327 | + } | |
10328 | + mux->shared_intr_buf = | |
10329 | + kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize), | |
10330 | + GFP_KERNEL); | |
10331 | + if (!mux->shared_intr_buf) | |
10332 | + goto exit; | |
10333 | + | |
10334 | + mutex_init(&mux->shared_int_lock); | |
10335 | + | |
10336 | + return mux; | |
10337 | + | |
10338 | +exit: | |
10339 | + kfree(mux->shared_intr_buf); | |
10340 | + usb_free_urb(mux->shared_intr_urb); | |
10341 | + kfree(mux); | |
10342 | + return NULL; | |
10343 | +} | |
10344 | + | |
10345 | +/* Gets the port spec for a certain interface */ | |
10346 | +static int hso_get_config_data(struct usb_interface *interface) | |
10347 | +{ | |
10348 | + struct usb_device *usbdev = interface_to_usbdev(interface); | |
10349 | + u8 *config_data = kmalloc(17, GFP_KERNEL); | |
10350 | + u32 if_num = interface->altsetting->desc.bInterfaceNumber; | |
10351 | + s32 result; | |
10352 | + | |
10353 | + if (!config_data) | |
10354 | + return -ENOMEM; | |
10355 | + if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), | |
10356 | + 0x86, 0xC0, 0, 0, config_data, 17, | |
10357 | + USB_CTRL_SET_TIMEOUT) != 0x11) { | |
10358 | + kfree(config_data); | |
10359 | + return -EIO; | |
10360 | + } | |
10361 | + | |
10362 | + switch (config_data[if_num]) { | |
10363 | + case 0x0: | |
10364 | + result = 0; | |
10365 | + break; | |
10366 | + case 0x1: | |
10367 | + result = HSO_PORT_DIAG; | |
10368 | + break; | |
10369 | + case 0x2: | |
10370 | + result = HSO_PORT_GPS; | |
10371 | + break; | |
10372 | + case 0x3: | |
10373 | + result = HSO_PORT_GPS_CONTROL; | |
10374 | + break; | |
10375 | + case 0x4: | |
10376 | + result = HSO_PORT_APP; | |
10377 | + break; | |
10378 | + case 0x5: | |
10379 | + result = HSO_PORT_APP2; | |
10380 | + break; | |
10381 | + case 0x6: | |
10382 | + result = HSO_PORT_CONTROL; | |
10383 | + break; | |
10384 | + case 0x7: | |
10385 | + result = HSO_PORT_NETWORK; | |
10386 | + break; | |
10387 | + case 0x8: | |
10388 | + result = HSO_PORT_MODEM; | |
10389 | + break; | |
10390 | + case 0x9: | |
10391 | + result = HSO_PORT_MSD; | |
10392 | + break; | |
10393 | + case 0xa: | |
10394 | + result = HSO_PORT_PCSC; | |
10395 | + break; | |
10396 | + case 0xb: | |
10397 | + result = HSO_PORT_VOICE; | |
10398 | + break; | |
10399 | + default: | |
10400 | + result = 0; | |
10401 | + } | |
10402 | + | |
10403 | + if (result) | |
10404 | + result |= HSO_INTF_BULK; | |
10405 | + | |
10406 | + if (config_data[16] & 0x1) | |
10407 | + result |= HSO_INFO_CRC_BUG; | |
10408 | + | |
10409 | + kfree(config_data); | |
10410 | + return result; | |
10411 | +} | |
10412 | + | |
10413 | +/* called once for each interface upon device insertion */ | |
10414 | +static int hso_probe(struct usb_interface *interface, | |
10415 | + const struct usb_device_id *id) | |
10416 | +{ | |
10417 | + int mux, i, if_num, port_spec; | |
10418 | + unsigned char port_mask; | |
10419 | + struct hso_device *hso_dev = NULL; | |
10420 | + struct hso_shared_int *shared_int; | |
10421 | + struct hso_device *tmp_dev = NULL; | |
10422 | + | |
10423 | + if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { | |
10424 | + dev_err(&interface->dev, "Not our interface\n"); | |
10425 | + return -ENODEV; | |
10426 | + } | |
10427 | + | |
10428 | + if_num = interface->altsetting->desc.bInterfaceNumber; | |
10429 | + | |
10430 | + /* Get the interface/port specification from either driver_info or from | |
10431 | + * the device itself */ | |
10432 | + if (id->driver_info) | |
10433 | + port_spec = ((u32 *)(id->driver_info))[if_num]; | |
10434 | + else | |
10435 | + port_spec = hso_get_config_data(interface); | |
10436 | + | |
10437 | + /* Check if we need to switch to alt interfaces prior to port | |
10438 | + * configuration */ | |
10439 | + if (interface->num_altsetting > 1) | |
10440 | + usb_set_interface(interface_to_usbdev(interface), if_num, 1); | |
10441 | + interface->needs_remote_wakeup = 1; | |
10442 | + | |
10443 | + /* Allocate new hso device(s) */ | |
10444 | + switch (port_spec & HSO_INTF_MASK) { | |
10445 | + case HSO_INTF_MUX: | |
10446 | + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { | |
10447 | + /* Create the network device */ | |
10448 | + if (!disable_net) { | |
10449 | + hso_dev = hso_create_net_device(interface, | |
10450 | + port_spec); | |
10451 | + if (!hso_dev) | |
10452 | + goto exit; | |
10453 | + tmp_dev = hso_dev; | |
10454 | + } | |
10455 | + } | |
10456 | + | |
10457 | + if (hso_get_mux_ports(interface, &port_mask)) | |
10458 | + /* TODO: de-allocate everything */ | |
10459 | + goto exit; | |
10460 | + | |
10461 | + shared_int = hso_create_shared_int(interface); | |
10462 | + if (!shared_int) | |
10463 | + goto exit; | |
10464 | + | |
10465 | + for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) { | |
10466 | + if (port_mask & i) { | |
10467 | + hso_dev = hso_create_mux_serial_device( | |
10468 | + interface, i, shared_int); | |
10469 | + if (!hso_dev) | |
10470 | + goto exit; | |
10471 | + } | |
10472 | + } | |
10473 | + | |
10474 | + if (tmp_dev) | |
10475 | + hso_dev = tmp_dev; | |
10476 | + break; | |
10477 | + | |
10478 | + case HSO_INTF_BULK: | |
10479 | + /* It's a regular bulk interface */ | |
10480 | + if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { | |
10481 | + if (!disable_net) | |
10482 | + hso_dev = | |
10483 | + hso_create_net_device(interface, port_spec); | |
10484 | + } else { | |
10485 | + hso_dev = | |
10486 | + hso_create_bulk_serial_device(interface, port_spec); | |
10487 | + } | |
10488 | + if (!hso_dev) | |
10489 | + goto exit; | |
10490 | + break; | |
10491 | + default: | |
10492 | + goto exit; | |
10493 | + } | |
10494 | + | |
10495 | + /* save our data pointer in this device */ | |
10496 | + usb_set_intfdata(interface, hso_dev); | |
10497 | + | |
10498 | + /* done */ | |
10499 | + return 0; | |
10500 | +exit: | |
10501 | + hso_free_interface(interface); | |
10502 | + return -ENODEV; | |
10503 | +} | |
10504 | + | |
10505 | +/* device removed, cleaning up */ | |
10506 | +static void hso_disconnect(struct usb_interface *interface) | |
10507 | +{ | |
10508 | + hso_free_interface(interface); | |
10509 | + | |
10510 | + /* remove reference of our private data */ | |
10511 | + usb_set_intfdata(interface, NULL); | |
10512 | +} | |
10513 | + | |
10514 | +static void async_get_intf(struct work_struct *data) | |
10515 | +{ | |
10516 | + struct hso_device *hso_dev = | |
10517 | + container_of(data, struct hso_device, async_get_intf); | |
10518 | + usb_autopm_get_interface(hso_dev->interface); | |
10519 | +} | |
10520 | + | |
10521 | +static void async_put_intf(struct work_struct *data) | |
10522 | +{ | |
10523 | + struct hso_device *hso_dev = | |
10524 | + container_of(data, struct hso_device, async_put_intf); | |
10525 | + usb_autopm_put_interface(hso_dev->interface); | |
10526 | +} | |
10527 | + | |
10528 | +static int hso_get_activity(struct hso_device *hso_dev) | |
10529 | +{ | |
10530 | + if (hso_dev->usb->state == USB_STATE_SUSPENDED) { | |
10531 | + if (!hso_dev->is_active) { | |
10532 | + hso_dev->is_active = 1; | |
10533 | + schedule_work(&hso_dev->async_get_intf); | |
10534 | + } | |
10535 | + } | |
10536 | + | |
10537 | + if (hso_dev->usb->state != USB_STATE_CONFIGURED) | |
10538 | + return -EAGAIN; | |
10539 | + | |
10540 | + usb_mark_last_busy(hso_dev->usb); | |
10541 | + | |
10542 | + return 0; | |
10543 | +} | |
10544 | + | |
10545 | +static int hso_put_activity(struct hso_device *hso_dev) | |
10546 | +{ | |
10547 | + if (hso_dev->usb->state != USB_STATE_SUSPENDED) { | |
10548 | + if (hso_dev->is_active) { | |
10549 | + hso_dev->is_active = 0; | |
10550 | + schedule_work(&hso_dev->async_put_intf); | |
10551 | + return -EAGAIN; | |
10552 | + } | |
10553 | + } | |
10554 | + hso_dev->is_active = 0; | |
10555 | + return 0; | |
10556 | +} | |
10557 | + | |
10558 | +/* called by kernel when we need to suspend device */ | |
10559 | +static int hso_suspend(struct usb_interface *iface, pm_message_t message) | |
10560 | +{ | |
10561 | + int i, result; | |
10562 | + | |
10563 | + /* Stop all serial ports */ | |
10564 | + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | |
10565 | + if (serial_table[i] && (serial_table[i]->interface == iface)) { | |
10566 | + result = hso_stop_serial_device(serial_table[i]); | |
10567 | + if (result) | |
10568 | + goto out; | |
10569 | + } | |
10570 | + } | |
10571 | + | |
10572 | + /* Stop all network ports */ | |
10573 | + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { | |
10574 | + if (network_table[i] && | |
10575 | + (network_table[i]->interface == iface)) { | |
10576 | + result = hso_stop_net_device(network_table[i]); | |
10577 | + if (result) | |
10578 | + goto out; | |
10579 | + } | |
10580 | + } | |
10581 | + | |
10582 | +out: | |
10583 | + return 0; | |
10584 | +} | |
10585 | + | |
10586 | +/* called by kernel when we need to resume device */ | |
10587 | +static int hso_resume(struct usb_interface *iface) | |
10588 | +{ | |
10589 | + int i, result = 0; | |
10590 | + struct hso_net *hso_net; | |
10591 | + | |
10592 | + /* Start all serial ports */ | |
10593 | + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | |
10594 | + if (serial_table[i] && (serial_table[i]->interface == iface)) { | |
10595 | + if (atomic_read(&dev2ser(serial_table[i])->port.count)) { | |
10596 | + result = | |
10597 | + hso_start_serial_device(serial_table[i], GFP_NOIO); | |
10598 | + hso_kick_transmit(dev2ser(serial_table[i])); | |
10599 | + if (result) | |
10600 | + goto out; | |
10601 | + } | |
10602 | + } | |
10603 | + } | |
10604 | + | |
10605 | + /* Start all network ports */ | |
10606 | + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { | |
10607 | + if (network_table[i] && | |
10608 | + (network_table[i]->interface == iface)) { | |
10609 | + hso_net = dev2net(network_table[i]); | |
10610 | + if (hso_net->flags & IFF_UP) { | |
10611 | + /* First transmit any lingering data, | |
10612 | + then restart the device. */ | |
10613 | + if (hso_net->skb_tx_buf) { | |
10614 | + dev_dbg(&iface->dev, | |
10615 | + "Transmitting" | |
10616 | + " lingering data\n"); | |
10617 | + hso_net_start_xmit(hso_net->skb_tx_buf, | |
10618 | + hso_net->net); | |
10619 | + hso_net->skb_tx_buf = NULL; | |
10620 | + } | |
10621 | + result = hso_start_net_device(network_table[i]); | |
10622 | + if (result) | |
10623 | + goto out; | |
10624 | + } | |
10625 | + } | |
10626 | + } | |
10627 | + | |
10628 | +out: | |
10629 | + return result; | |
10630 | +} | |
10631 | + | |
10632 | +static void reset_device(struct work_struct *data) | |
10633 | +{ | |
10634 | + struct hso_device *hso_dev = | |
10635 | + container_of(data, struct hso_device, reset_device); | |
10636 | + struct usb_device *usb = hso_dev->usb; | |
10637 | + int result; | |
10638 | + | |
10639 | + if (hso_dev->usb_gone) { | |
10640 | + D1("No reset during disconnect\n"); | |
10641 | + } else { | |
10642 | + result = usb_lock_device_for_reset(usb, hso_dev->interface); | |
10643 | + if (result < 0) | |
10644 | + D1("unable to lock device for reset: %d\n", result); | |
10645 | + else { | |
10646 | + usb_reset_device(usb); | |
10647 | + usb_unlock_device(usb); | |
10648 | + } | |
10649 | + } | |
10650 | +} | |
10651 | + | |
10652 | +static void hso_serial_ref_free(struct kref *ref) | |
10653 | +{ | |
10654 | + struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); | |
10655 | + | |
10656 | + hso_free_serial_device(hso_dev); | |
10657 | +} | |
10658 | + | |
10659 | +static void hso_free_interface(struct usb_interface *interface) | |
10660 | +{ | |
10661 | + struct hso_serial *hso_dev; | |
10662 | + int i; | |
10663 | + | |
10664 | + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | |
10665 | + if (serial_table[i] && | |
10666 | + (serial_table[i]->interface == interface)) { | |
10667 | + hso_dev = dev2ser(serial_table[i]); | |
10668 | + tty_port_tty_hangup(&hso_dev->port, false); | |
10669 | + mutex_lock(&hso_dev->parent->mutex); | |
10670 | + hso_dev->parent->usb_gone = 1; | |
10671 | + mutex_unlock(&hso_dev->parent->mutex); | |
10672 | + kref_put(&serial_table[i]->ref, hso_serial_ref_free); | |
10673 | + } | |
10674 | + } | |
10675 | + | |
10676 | + for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { | |
10677 | + if (network_table[i] && | |
10678 | + (network_table[i]->interface == interface)) { | |
10679 | + struct rfkill *rfk = dev2net(network_table[i])->rfkill; | |
10680 | + /* hso_stop_net_device doesn't stop the net queue since | |
10681 | + * traffic needs to start it again when suspended */ | |
10682 | + netif_stop_queue(dev2net(network_table[i])->net); | |
10683 | + hso_stop_net_device(network_table[i]); | |
10684 | + cancel_work_sync(&network_table[i]->async_put_intf); | |
10685 | + cancel_work_sync(&network_table[i]->async_get_intf); | |
10686 | + if (rfk) { | |
10687 | + rfkill_unregister(rfk); | |
10688 | + rfkill_destroy(rfk); | |
10689 | + } | |
10690 | + hso_free_net_device(network_table[i]); | |
10691 | + } | |
10692 | + } | |
10693 | +} | |
10694 | + | |
10695 | +/* Helper functions */ | |
10696 | + | |
10697 | +/* Get the endpoint ! */ | |
10698 | +static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, | |
10699 | + int type, int dir) | |
10700 | +{ | |
10701 | + int i; | |
10702 | + struct usb_host_interface *iface = intf->cur_altsetting; | |
10703 | + struct usb_endpoint_descriptor *endp; | |
10704 | + | |
10705 | + for (i = 0; i < iface->desc.bNumEndpoints; i++) { | |
10706 | + endp = &iface->endpoint[i].desc; | |
10707 | + if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) && | |
10708 | + (usb_endpoint_type(endp) == type)) | |
10709 | + return endp; | |
10710 | + } | |
10711 | + | |
10712 | + return NULL; | |
10713 | +} | |
10714 | + | |
10715 | +/* Get the byte that describes which ports are enabled */ | |
10716 | +static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports) | |
10717 | +{ | |
10718 | + int i; | |
10719 | + struct usb_host_interface *iface = intf->cur_altsetting; | |
10720 | + | |
10721 | + if (iface->extralen == 3) { | |
10722 | + *ports = iface->extra[2]; | |
10723 | + return 0; | |
10724 | + } | |
10725 | + | |
10726 | + for (i = 0; i < iface->desc.bNumEndpoints; i++) { | |
10727 | + if (iface->endpoint[i].extralen == 3) { | |
10728 | + *ports = iface->endpoint[i].extra[2]; | |
10729 | + return 0; | |
10730 | + } | |
10731 | + } | |
10732 | + | |
10733 | + return -1; | |
10734 | +} | |
10735 | + | |
10736 | +/* interrupt urb needs to be submitted, used for serial read of muxed port */ | |
10737 | +static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int, | |
10738 | + struct usb_device *usb, gfp_t gfp) | |
10739 | +{ | |
10740 | + int result; | |
10741 | + | |
10742 | + usb_fill_int_urb(shared_int->shared_intr_urb, usb, | |
10743 | + usb_rcvintpipe(usb, | |
10744 | + shared_int->intr_endp->bEndpointAddress & 0x7F), | |
10745 | + shared_int->shared_intr_buf, | |
10746 | + 1, | |
10747 | + intr_callback, shared_int, | |
10748 | + shared_int->intr_endp->bInterval); | |
10749 | + | |
10750 | + result = usb_submit_urb(shared_int->shared_intr_urb, gfp); | |
10751 | + if (result) | |
10752 | + dev_warn(&usb->dev, "%s failed mux_intr_urb %d\n", __func__, | |
10753 | + result); | |
10754 | + | |
10755 | + return result; | |
10756 | +} | |
10757 | + | |
10758 | +/* operations setup of the serial interface */ | |
10759 | +static const struct tty_operations hso_serial_ops = { | |
10760 | + .open = hso_serial_open, | |
10761 | + .close = hso_serial_close, | |
10762 | + .write = hso_serial_write, | |
10763 | + .write_room = hso_serial_write_room, | |
10764 | + .ioctl = hso_serial_ioctl, | |
10765 | + .set_termios = hso_serial_set_termios, | |
10766 | + .chars_in_buffer = hso_serial_chars_in_buffer, | |
10767 | + .tiocmget = hso_serial_tiocmget, | |
10768 | + .tiocmset = hso_serial_tiocmset, | |
10769 | + .get_icount = hso_get_count, | |
10770 | + .unthrottle = hso_unthrottle | |
10771 | +}; | |
10772 | + | |
10773 | +static struct usb_driver hso_driver = { | |
10774 | + .name = driver_name, | |
10775 | + .probe = hso_probe, | |
10776 | + .disconnect = hso_disconnect, | |
10777 | + .id_table = hso_ids, | |
10778 | + .suspend = hso_suspend, | |
10779 | + .resume = hso_resume, | |
10780 | + .reset_resume = hso_resume, | |
10781 | + .supports_autosuspend = 1, | |
10782 | + .disable_hub_initiated_lpm = 1, | |
10783 | +}; | |
10784 | + | |
10785 | +static int __init hso_init(void) | |
10786 | +{ | |
10787 | + int i; | |
10788 | + int result; | |
10789 | + | |
10790 | + /* put it in the log */ | |
10791 | + printk(KERN_INFO "hso: %s\n", version); | |
10792 | + | |
10793 | + /* Initialise the serial table semaphore and table */ | |
10794 | + spin_lock_init(&serial_table_lock); | |
10795 | + for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) | |
10796 | + serial_table[i] = NULL; | |
10797 | + | |
10798 | + /* allocate our driver using the proper amount of supported minors */ | |
10799 | + tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); | |
10800 | + if (!tty_drv) | |
10801 | + return -ENOMEM; | |
10802 | + | |
10803 | + /* fill in all needed values */ | |
10804 | + tty_drv->driver_name = driver_name; | |
10805 | + tty_drv->name = tty_filename; | |
10806 | + | |
10807 | + /* if major number is provided as parameter, use that one */ | |
10808 | + if (tty_major) | |
10809 | + tty_drv->major = tty_major; | |
10810 | + | |
10811 | + tty_drv->minor_start = 0; | |
10812 | + tty_drv->type = TTY_DRIVER_TYPE_SERIAL; | |
10813 | + tty_drv->subtype = SERIAL_TYPE_NORMAL; | |
10814 | + tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | |
10815 | + tty_drv->init_termios = tty_std_termios; | |
10816 | + hso_init_termios(&tty_drv->init_termios); | |
10817 | + tty_set_operations(tty_drv, &hso_serial_ops); | |
10818 | + | |
10819 | + /* register the tty driver */ | |
10820 | + result = tty_register_driver(tty_drv); | |
10821 | + if (result) { | |
10822 | + printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", | |
10823 | + __func__, result); | |
10824 | + goto err_free_tty; | |
10825 | + } | |
10826 | + | |
10827 | + /* register this module as an usb driver */ | |
10828 | + result = usb_register(&hso_driver); | |
10829 | + if (result) { | |
10830 | + printk(KERN_ERR "Could not register hso driver? error: %d\n", | |
10831 | + result); | |
10832 | + goto err_unreg_tty; | |
10833 | + } | |
10834 | + | |
10835 | + /* done */ | |
10836 | + return 0; | |
10837 | +err_unreg_tty: | |
10838 | + tty_unregister_driver(tty_drv); | |
10839 | +err_free_tty: | |
10840 | + put_tty_driver(tty_drv); | |
10841 | + return result; | |
10842 | +} | |
10843 | + | |
10844 | +static void __exit hso_exit(void) | |
10845 | +{ | |
10846 | + printk(KERN_INFO "hso: unloaded\n"); | |
10847 | + | |
10848 | + tty_unregister_driver(tty_drv); | |
10849 | + put_tty_driver(tty_drv); | |
10850 | + /* deregister the usb driver */ | |
10851 | + usb_deregister(&hso_driver); | |
10852 | +} | |
10853 | + | |
10854 | +/* Module definitions */ | |
10855 | +module_init(hso_init); | |
10856 | +module_exit(hso_exit); | |
10857 | + | |
10858 | +MODULE_AUTHOR(MOD_AUTHOR); | |
10859 | +MODULE_DESCRIPTION(MOD_DESCRIPTION); | |
10860 | +MODULE_LICENSE(MOD_LICENSE); | |
10861 | + | |
10862 | +/* change the debug level (eg: insmod hso.ko debug=0x04) */ | |
10863 | +MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]"); | |
10864 | +module_param(debug, int, S_IRUGO | S_IWUSR); | |
10865 | + | |
10866 | +/* set the major tty number (eg: insmod hso.ko tty_major=245) */ | |
10867 | +MODULE_PARM_DESC(tty_major, "Set the major tty number"); | |
10868 | +module_param(tty_major, int, S_IRUGO | S_IWUSR); | |
10869 | + | |
10870 | +/* disable network interface (eg: insmod hso.ko disable_net=1) */ | |
10871 | +MODULE_PARM_DESC(disable_net, "Disable the network interface"); | |
10872 | +module_param(disable_net, int, S_IRUGO | S_IWUSR); | |
10873 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/huawei_cdc_ncm.c backports-3.18.1-1/drivers/net/usb/huawei_cdc_ncm.c | |
10874 | --- backports-3.18.1-1.org/drivers/net/usb/huawei_cdc_ncm.c 1970-01-01 01:00:00.000000000 +0100 | |
10875 | +++ backports-3.18.1-1/drivers/net/usb/huawei_cdc_ncm.c 2014-12-16 18:39:45.000000000 +0100 | |
10876 | @@ -0,0 +1,221 @@ | |
10877 | +/* huawei_cdc_ncm.c - handles Huawei devices using the CDC NCM protocol as | |
10878 | + * transport layer. | |
10879 | + * Copyright (C) 2013 Enrico Mioso <mrkiko.rs@gmail.com> | |
10880 | + * | |
10881 | + * | |
10882 | + * ABSTRACT: | |
10883 | + * This driver handles devices resembling the CDC NCM standard, but | |
10884 | + * encapsulating another protocol inside it. An example are some Huawei 3G | |
10885 | + * devices, exposing an embedded AT channel where you can set up the NCM | |
10886 | + * connection. | |
10887 | + * This code has been heavily inspired by the cdc_mbim.c driver, which is | |
10888 | + * Copyright (c) 2012 Smith Micro Software, Inc. | |
10889 | + * Copyright (c) 2012 Bjørn Mork <bjorn@mork.no> | |
10890 | + * | |
10891 | + * This program is free software; you can redistribute it and/or | |
10892 | + * modify it under the terms of the GNU General Public License | |
10893 | + * version 2 as published by the Free Software Foundation. | |
10894 | + */ | |
10895 | + | |
10896 | +#include <linux/module.h> | |
10897 | +#include <linux/netdevice.h> | |
10898 | +#include <linux/ethtool.h> | |
10899 | +#include <linux/if_vlan.h> | |
10900 | +#include <linux/ip.h> | |
10901 | +#include <linux/mii.h> | |
10902 | +#include <linux/usb.h> | |
10903 | +#include <linux/usb/cdc.h> | |
10904 | +#include <linux/usb/usbnet.h> | |
10905 | +#include <linux/usb/cdc-wdm.h> | |
10906 | +#include <linux/usb/cdc_ncm.h> | |
10907 | + | |
10908 | +/* Driver data */ | |
10909 | +struct huawei_cdc_ncm_state { | |
10910 | + struct cdc_ncm_ctx *ctx; | |
10911 | + atomic_t pmcount; | |
10912 | + struct usb_driver *subdriver; | |
10913 | + struct usb_interface *control; | |
10914 | + struct usb_interface *data; | |
10915 | +}; | |
10916 | + | |
10917 | +static int huawei_cdc_ncm_manage_power(struct usbnet *usbnet_dev, int on) | |
10918 | +{ | |
10919 | + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; | |
10920 | + int rv; | |
10921 | + | |
10922 | + if ((on && atomic_add_return(1, &drvstate->pmcount) == 1) || | |
10923 | + (!on && atomic_dec_and_test(&drvstate->pmcount))) { | |
10924 | + rv = usb_autopm_get_interface(usbnet_dev->intf); | |
10925 | + usbnet_dev->intf->needs_remote_wakeup = on; | |
10926 | + if (!rv) | |
10927 | + usb_autopm_put_interface(usbnet_dev->intf); | |
10928 | + } | |
10929 | + return 0; | |
10930 | +} | |
10931 | + | |
10932 | +static int huawei_cdc_ncm_wdm_manage_power(struct usb_interface *intf, | |
10933 | + int status) | |
10934 | +{ | |
10935 | + struct usbnet *usbnet_dev = usb_get_intfdata(intf); | |
10936 | + | |
10937 | + /* can be called while disconnecting */ | |
10938 | + if (!usbnet_dev) | |
10939 | + return 0; | |
10940 | + | |
10941 | + return huawei_cdc_ncm_manage_power(usbnet_dev, status); | |
10942 | +} | |
10943 | + | |
10944 | + | |
10945 | +static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, | |
10946 | + struct usb_interface *intf) | |
10947 | +{ | |
10948 | + struct cdc_ncm_ctx *ctx; | |
10949 | + struct usb_driver *subdriver = ERR_PTR(-ENODEV); | |
10950 | + int ret = -ENODEV; | |
10951 | + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; | |
10952 | + | |
10953 | + /* altsetting should always be 1 for NCM devices - so we hard-coded | |
10954 | + * it here | |
10955 | + */ | |
10956 | + ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); | |
10957 | + if (ret) | |
10958 | + goto err; | |
10959 | + | |
10960 | + ctx = drvstate->ctx; | |
10961 | + | |
10962 | + if (usbnet_dev->status) | |
10963 | + /* The wMaxCommand buffer must be big enough to hold | |
10964 | + * any message from the modem. Experience has shown | |
10965 | + * that some replies are more than 256 bytes long | |
10966 | + */ | |
10967 | + subdriver = usb_cdc_wdm_register(ctx->control, | |
10968 | + &usbnet_dev->status->desc, | |
10969 | + 1024, /* wMaxCommand */ | |
10970 | + huawei_cdc_ncm_wdm_manage_power); | |
10971 | + if (IS_ERR(subdriver)) { | |
10972 | + ret = PTR_ERR(subdriver); | |
10973 | + cdc_ncm_unbind(usbnet_dev, intf); | |
10974 | + goto err; | |
10975 | + } | |
10976 | + | |
10977 | + /* Prevent usbnet from using the status descriptor */ | |
10978 | + usbnet_dev->status = NULL; | |
10979 | + | |
10980 | + drvstate->subdriver = subdriver; | |
10981 | + | |
10982 | +err: | |
10983 | + return ret; | |
10984 | +} | |
10985 | + | |
10986 | +static void huawei_cdc_ncm_unbind(struct usbnet *usbnet_dev, | |
10987 | + struct usb_interface *intf) | |
10988 | +{ | |
10989 | + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; | |
10990 | + struct cdc_ncm_ctx *ctx = drvstate->ctx; | |
10991 | + | |
10992 | + if (drvstate->subdriver && drvstate->subdriver->disconnect) | |
10993 | + drvstate->subdriver->disconnect(ctx->control); | |
10994 | + drvstate->subdriver = NULL; | |
10995 | + | |
10996 | + cdc_ncm_unbind(usbnet_dev, intf); | |
10997 | +} | |
10998 | + | |
10999 | +static int huawei_cdc_ncm_suspend(struct usb_interface *intf, | |
11000 | + pm_message_t message) | |
11001 | +{ | |
11002 | + int ret = 0; | |
11003 | + struct usbnet *usbnet_dev = usb_get_intfdata(intf); | |
11004 | + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; | |
11005 | + struct cdc_ncm_ctx *ctx = drvstate->ctx; | |
11006 | + | |
11007 | + if (ctx == NULL) { | |
11008 | + ret = -ENODEV; | |
11009 | + goto error; | |
11010 | + } | |
11011 | + | |
11012 | + ret = usbnet_suspend(intf, message); | |
11013 | + if (ret < 0) | |
11014 | + goto error; | |
11015 | + | |
11016 | + if (intf == ctx->control && | |
11017 | + drvstate->subdriver && | |
11018 | + drvstate->subdriver->suspend) | |
11019 | + ret = drvstate->subdriver->suspend(intf, message); | |
11020 | + if (ret < 0) | |
11021 | + usbnet_resume(intf); | |
11022 | + | |
11023 | +error: | |
11024 | + return ret; | |
11025 | +} | |
11026 | + | |
11027 | +static int huawei_cdc_ncm_resume(struct usb_interface *intf) | |
11028 | +{ | |
11029 | + int ret = 0; | |
11030 | + struct usbnet *usbnet_dev = usb_get_intfdata(intf); | |
11031 | + struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; | |
11032 | + bool callsub; | |
11033 | + struct cdc_ncm_ctx *ctx = drvstate->ctx; | |
11034 | + | |
11035 | + /* should we call subdriver's resume function? */ | |
11036 | + callsub = | |
11037 | + (intf == ctx->control && | |
11038 | + drvstate->subdriver && | |
11039 | + drvstate->subdriver->resume); | |
11040 | + | |
11041 | + if (callsub) | |
11042 | + ret = drvstate->subdriver->resume(intf); | |
11043 | + if (ret < 0) | |
11044 | + goto err; | |
11045 | + ret = usbnet_resume(intf); | |
11046 | + if (ret < 0 && callsub) | |
11047 | + drvstate->subdriver->suspend(intf, PMSG_SUSPEND); | |
11048 | +err: | |
11049 | + return ret; | |
11050 | +} | |
11051 | + | |
11052 | +static const struct driver_info huawei_cdc_ncm_info = { | |
11053 | + .description = "Huawei CDC NCM device", | |
11054 | + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, | |
11055 | + .bind = huawei_cdc_ncm_bind, | |
11056 | + .unbind = huawei_cdc_ncm_unbind, | |
11057 | + .manage_power = huawei_cdc_ncm_manage_power, | |
11058 | + .rx_fixup = cdc_ncm_rx_fixup, | |
11059 | + .tx_fixup = cdc_ncm_tx_fixup, | |
11060 | +}; | |
11061 | + | |
11062 | +static const struct usb_device_id huawei_cdc_ncm_devs[] = { | |
11063 | + /* Huawei NCM devices disguised as vendor specific */ | |
11064 | + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16), | |
11065 | + .driver_info = (unsigned long)&huawei_cdc_ncm_info, | |
11066 | + }, | |
11067 | + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46), | |
11068 | + .driver_info = (unsigned long)&huawei_cdc_ncm_info, | |
11069 | + }, | |
11070 | + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76), | |
11071 | + .driver_info = (unsigned long)&huawei_cdc_ncm_info, | |
11072 | + }, | |
11073 | + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x03, 0x16), | |
11074 | + .driver_info = (unsigned long)&huawei_cdc_ncm_info, | |
11075 | + }, | |
11076 | + | |
11077 | + /* Terminating entry */ | |
11078 | + { | |
11079 | + }, | |
11080 | +}; | |
11081 | +MODULE_DEVICE_TABLE(usb, huawei_cdc_ncm_devs); | |
11082 | + | |
11083 | +static struct usb_driver huawei_cdc_ncm_driver = { | |
11084 | + .name = "huawei_cdc_ncm", | |
11085 | + .id_table = huawei_cdc_ncm_devs, | |
11086 | + .probe = usbnet_probe, | |
11087 | + .disconnect = usbnet_disconnect, | |
11088 | + .suspend = huawei_cdc_ncm_suspend, | |
11089 | + .resume = huawei_cdc_ncm_resume, | |
11090 | + .reset_resume = huawei_cdc_ncm_resume, | |
11091 | + .supports_autosuspend = 1, | |
11092 | + .disable_hub_initiated_lpm = 1, | |
11093 | +}; | |
11094 | +module_usb_driver(huawei_cdc_ncm_driver); | |
11095 | +MODULE_AUTHOR("Enrico Mioso <mrkiko.rs@gmail.com>"); | |
11096 | +MODULE_DESCRIPTION("USB CDC NCM host driver with encapsulated protocol support"); | |
11097 | +MODULE_LICENSE("GPL"); | |
11098 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/int51x1.c backports-3.18.1-1/drivers/net/usb/int51x1.c | |
11099 | --- backports-3.18.1-1.org/drivers/net/usb/int51x1.c 1970-01-01 01:00:00.000000000 +0100 | |
11100 | +++ backports-3.18.1-1/drivers/net/usb/int51x1.c 2014-12-16 18:39:45.000000000 +0100 | |
11101 | @@ -0,0 +1,199 @@ | |
11102 | +/* | |
11103 | + * Copyright (c) 2009 Peter Holik | |
11104 | + * | |
11105 | + * Intellon usb PLC (Powerline Communications) usb net driver | |
11106 | + * | |
11107 | + * http://www.tandel.be/downloads/INT51X1_Datasheet.pdf | |
11108 | + * | |
11109 | + * Based on the work of Jan 'RedBully' Seiffert | |
11110 | + */ | |
11111 | + | |
11112 | +/* | |
11113 | + * This program is free software; you can redistribute it and/or modify | |
11114 | + * it under the terms of the GNU General Public License as published by | |
11115 | + * the Free Software Foundation; either version 2 of the License, or. | |
11116 | + * (at your option) any later version. | |
11117 | + * | |
11118 | + * This program is distributed in the hope that it will be useful, | |
11119 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11120 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11121 | + * GNU General Public License for more details. | |
11122 | + * | |
11123 | + * You should have received a copy of the GNU General Public License | |
11124 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
11125 | + */ | |
11126 | + | |
11127 | +#include <linux/module.h> | |
11128 | +#include <linux/ctype.h> | |
11129 | +#include <linux/netdevice.h> | |
11130 | +#include <linux/etherdevice.h> | |
11131 | +#include <linux/ethtool.h> | |
11132 | +#include <linux/slab.h> | |
11133 | +#include <linux/mii.h> | |
11134 | +#include <linux/usb.h> | |
11135 | +#include <linux/usb/usbnet.h> | |
11136 | + | |
11137 | +#define INT51X1_VENDOR_ID 0x09e1 | |
11138 | +#define INT51X1_PRODUCT_ID 0x5121 | |
11139 | + | |
11140 | +#define INT51X1_HEADER_SIZE 2 /* 2 byte header */ | |
11141 | + | |
11142 | +#define PACKET_TYPE_PROMISCUOUS (1 << 0) | |
11143 | +#define PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ | |
11144 | +#define PACKET_TYPE_DIRECTED (1 << 2) | |
11145 | +#define PACKET_TYPE_BROADCAST (1 << 3) | |
11146 | +#define PACKET_TYPE_MULTICAST (1 << 4) /* filtered */ | |
11147 | + | |
11148 | +#define SET_ETHERNET_PACKET_FILTER 0x43 | |
11149 | + | |
11150 | +static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
11151 | +{ | |
11152 | + int len; | |
11153 | + | |
11154 | + if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) { | |
11155 | + netdev_err(dev->net, "unexpected tiny rx frame\n"); | |
11156 | + return 0; | |
11157 | + } | |
11158 | + | |
11159 | + len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]); | |
11160 | + | |
11161 | + skb_trim(skb, len); | |
11162 | + | |
11163 | + return 1; | |
11164 | +} | |
11165 | + | |
11166 | +static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev, | |
11167 | + struct sk_buff *skb, gfp_t flags) | |
11168 | +{ | |
11169 | + int pack_len = skb->len; | |
11170 | + int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE; | |
11171 | + int headroom = skb_headroom(skb); | |
11172 | + int tailroom = skb_tailroom(skb); | |
11173 | + int need_tail = 0; | |
11174 | + __le16 *len; | |
11175 | + | |
11176 | + /* if packet and our header is smaler than 64 pad to 64 (+ ZLP) */ | |
11177 | + if ((pack_with_header_len) < dev->maxpacket) | |
11178 | + need_tail = dev->maxpacket - pack_with_header_len + 1; | |
11179 | + /* | |
11180 | + * usbnet would send a ZLP if packetlength mod urbsize == 0 for us, | |
11181 | + * but we need to know ourself, because this would add to the length | |
11182 | + * we send down to the device... | |
11183 | + */ | |
11184 | + else if (!(pack_with_header_len % dev->maxpacket)) | |
11185 | + need_tail = 1; | |
11186 | + | |
11187 | + if (!skb_cloned(skb) && | |
11188 | + (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) { | |
11189 | + if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) { | |
11190 | + skb->data = memmove(skb->head + INT51X1_HEADER_SIZE, | |
11191 | + skb->data, skb->len); | |
11192 | + skb_set_tail_pointer(skb, skb->len); | |
11193 | + } | |
11194 | + } else { | |
11195 | + struct sk_buff *skb2; | |
11196 | + | |
11197 | + skb2 = skb_copy_expand(skb, | |
11198 | + INT51X1_HEADER_SIZE, | |
11199 | + need_tail, | |
11200 | + flags); | |
11201 | + dev_kfree_skb_any(skb); | |
11202 | + if (!skb2) | |
11203 | + return NULL; | |
11204 | + skb = skb2; | |
11205 | + } | |
11206 | + | |
11207 | + pack_len += need_tail; | |
11208 | + pack_len &= 0x07ff; | |
11209 | + | |
11210 | + len = (__le16 *) __skb_push(skb, INT51X1_HEADER_SIZE); | |
11211 | + *len = cpu_to_le16(pack_len); | |
11212 | + | |
11213 | + if(need_tail) | |
11214 | + memset(__skb_put(skb, need_tail), 0, need_tail); | |
11215 | + | |
11216 | + return skb; | |
11217 | +} | |
11218 | + | |
11219 | +static void int51x1_set_multicast(struct net_device *netdev) | |
11220 | +{ | |
11221 | + struct usbnet *dev = netdev_priv(netdev); | |
11222 | + u16 filter = PACKET_TYPE_DIRECTED | PACKET_TYPE_BROADCAST; | |
11223 | + | |
11224 | + if (netdev->flags & IFF_PROMISC) { | |
11225 | + /* do not expect to see traffic of other PLCs */ | |
11226 | + filter |= PACKET_TYPE_PROMISCUOUS; | |
11227 | + netdev_info(dev->net, "promiscuous mode enabled\n"); | |
11228 | + } else if (!netdev_mc_empty(netdev) || | |
11229 | + (netdev->flags & IFF_ALLMULTI)) { | |
11230 | + filter |= PACKET_TYPE_ALL_MULTICAST; | |
11231 | + netdev_dbg(dev->net, "receive all multicast enabled\n"); | |
11232 | + } else { | |
11233 | + /* ~PROMISCUOUS, ~MULTICAST */ | |
11234 | + netdev_dbg(dev->net, "receive own packets only\n"); | |
11235 | + } | |
11236 | + | |
11237 | + usbnet_write_cmd_async(dev, SET_ETHERNET_PACKET_FILTER, | |
11238 | + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | |
11239 | + filter, 0, NULL, 0); | |
11240 | +} | |
11241 | + | |
11242 | +static const struct net_device_ops int51x1_netdev_ops = { | |
11243 | + .ndo_open = usbnet_open, | |
11244 | + .ndo_stop = usbnet_stop, | |
11245 | + .ndo_start_xmit = usbnet_start_xmit, | |
11246 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
11247 | + .ndo_change_mtu = usbnet_change_mtu, | |
11248 | + .ndo_set_mac_address = eth_mac_addr, | |
11249 | + .ndo_validate_addr = eth_validate_addr, | |
11250 | + .ndo_set_rx_mode = int51x1_set_multicast, | |
11251 | +}; | |
11252 | + | |
11253 | +static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf) | |
11254 | +{ | |
11255 | + int status = usbnet_get_ethernet_addr(dev, 3); | |
11256 | + | |
11257 | + if (status) | |
11258 | + return status; | |
11259 | + | |
11260 | + dev->net->hard_header_len += INT51X1_HEADER_SIZE; | |
11261 | + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | |
11262 | + dev->net->netdev_ops = &int51x1_netdev_ops; | |
11263 | + | |
11264 | + return usbnet_get_endpoints(dev, intf); | |
11265 | +} | |
11266 | + | |
11267 | +static const struct driver_info int51x1_info = { | |
11268 | + .description = "Intellon usb powerline adapter", | |
11269 | + .bind = int51x1_bind, | |
11270 | + .rx_fixup = int51x1_rx_fixup, | |
11271 | + .tx_fixup = int51x1_tx_fixup, | |
11272 | + .in = 1, | |
11273 | + .out = 2, | |
11274 | + .flags = FLAG_ETHER, | |
11275 | +}; | |
11276 | + | |
11277 | +static const struct usb_device_id products[] = { | |
11278 | + { | |
11279 | + USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID), | |
11280 | + .driver_info = (unsigned long) &int51x1_info, | |
11281 | + }, | |
11282 | + {}, | |
11283 | +}; | |
11284 | +MODULE_DEVICE_TABLE(usb, products); | |
11285 | + | |
11286 | +static struct usb_driver int51x1_driver = { | |
11287 | + .name = "int51x1", | |
11288 | + .id_table = products, | |
11289 | + .probe = usbnet_probe, | |
11290 | + .disconnect = usbnet_disconnect, | |
11291 | + .suspend = usbnet_suspend, | |
11292 | + .resume = usbnet_resume, | |
11293 | + .disable_hub_initiated_lpm = 1, | |
11294 | +}; | |
11295 | + | |
11296 | +module_usb_driver(int51x1_driver); | |
11297 | + | |
11298 | +MODULE_AUTHOR("Peter Holik"); | |
11299 | +MODULE_DESCRIPTION("Intellon usb powerline adapter"); | |
11300 | +MODULE_LICENSE("GPL"); | |
11301 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/ipheth.c backports-3.18.1-1/drivers/net/usb/ipheth.c | |
11302 | --- backports-3.18.1-1.org/drivers/net/usb/ipheth.c 1970-01-01 01:00:00.000000000 +0100 | |
11303 | +++ backports-3.18.1-1/drivers/net/usb/ipheth.c 2014-12-16 18:39:45.000000000 +0100 | |
11304 | @@ -0,0 +1,588 @@ | |
11305 | +/* | |
11306 | + * ipheth.c - Apple iPhone USB Ethernet driver | |
11307 | + * | |
11308 | + * Copyright (c) 2009 Diego Giagio <diego@giagio.com> | |
11309 | + * All rights reserved. | |
11310 | + * | |
11311 | + * Redistribution and use in source and binary forms, with or without | |
11312 | + * modification, are permitted provided that the following conditions | |
11313 | + * are met: | |
11314 | + * 1. Redistributions of source code must retain the above copyright | |
11315 | + * notice, this list of conditions and the following disclaimer. | |
11316 | + * 2. Redistributions in binary form must reproduce the above copyright | |
11317 | + * notice, this list of conditions and the following disclaimer in the | |
11318 | + * documentation and/or other materials provided with the distribution. | |
11319 | + * 3. Neither the name of GIAGIO.COM nor the names of its contributors | |
11320 | + * may be used to endorse or promote products derived from this software | |
11321 | + * without specific prior written permission. | |
11322 | + * | |
11323 | + * Alternatively, provided that this notice is retained in full, this | |
11324 | + * software may be distributed under the terms of the GNU General | |
11325 | + * Public License ("GPL") version 2, in which case the provisions of the | |
11326 | + * GPL apply INSTEAD OF those given above. | |
11327 | + * | |
11328 | + * The provided data structures and external interfaces from this code | |
11329 | + * are not restricted to be used by modules with a GPL compatible license. | |
11330 | + * | |
11331 | + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
11332 | + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
11333 | + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
11334 | + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
11335 | + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
11336 | + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
11337 | + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
11338 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
11339 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
11340 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
11341 | + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
11342 | + * DAMAGE. | |
11343 | + * | |
11344 | + * | |
11345 | + * Attention: iPhone device must be paired, otherwise it won't respond to our | |
11346 | + * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver | |
11347 | + * | |
11348 | + */ | |
11349 | + | |
11350 | +#include <linux/kernel.h> | |
11351 | +#include <linux/errno.h> | |
11352 | +#include <linux/slab.h> | |
11353 | +#include <linux/module.h> | |
11354 | +#include <linux/netdevice.h> | |
11355 | +#include <linux/etherdevice.h> | |
11356 | +#include <linux/ethtool.h> | |
11357 | +#include <linux/usb.h> | |
11358 | +#include <linux/workqueue.h> | |
11359 | + | |
11360 | +#define USB_VENDOR_APPLE 0x05ac | |
11361 | +#define USB_PRODUCT_IPHONE 0x1290 | |
11362 | +#define USB_PRODUCT_IPHONE_3G 0x1292 | |
11363 | +#define USB_PRODUCT_IPHONE_3GS 0x1294 | |
11364 | +#define USB_PRODUCT_IPHONE_4 0x1297 | |
11365 | +#define USB_PRODUCT_IPAD 0x129a | |
11366 | +#define USB_PRODUCT_IPAD_2 0x12a2 | |
11367 | +#define USB_PRODUCT_IPAD_3 0x12a6 | |
11368 | +#define USB_PRODUCT_IPAD_MINI 0x12ab | |
11369 | +#define USB_PRODUCT_IPHONE_4_VZW 0x129c | |
11370 | +#define USB_PRODUCT_IPHONE_4S 0x12a0 | |
11371 | +#define USB_PRODUCT_IPHONE_5 0x12a8 | |
11372 | + | |
11373 | +#define IPHETH_USBINTF_CLASS 255 | |
11374 | +#define IPHETH_USBINTF_SUBCLASS 253 | |
11375 | +#define IPHETH_USBINTF_PROTO 1 | |
11376 | + | |
11377 | +#define IPHETH_BUF_SIZE 1516 | |
11378 | +#define IPHETH_IP_ALIGN 2 /* padding at front of URB */ | |
11379 | +#define IPHETH_TX_TIMEOUT (5 * HZ) | |
11380 | + | |
11381 | +#define IPHETH_INTFNUM 2 | |
11382 | +#define IPHETH_ALT_INTFNUM 1 | |
11383 | + | |
11384 | +#define IPHETH_CTRL_ENDP 0x00 | |
11385 | +#define IPHETH_CTRL_BUF_SIZE 0x40 | |
11386 | +#define IPHETH_CTRL_TIMEOUT (5 * HZ) | |
11387 | + | |
11388 | +#define IPHETH_CMD_GET_MACADDR 0x00 | |
11389 | +#define IPHETH_CMD_CARRIER_CHECK 0x45 | |
11390 | + | |
11391 | +#define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) | |
11392 | +#define IPHETH_CARRIER_ON 0x04 | |
11393 | + | |
11394 | +static struct usb_device_id ipheth_table[] = { | |
11395 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11396 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE, | |
11397 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11398 | + IPHETH_USBINTF_PROTO) }, | |
11399 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11400 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3G, | |
11401 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11402 | + IPHETH_USBINTF_PROTO) }, | |
11403 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11404 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS, | |
11405 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11406 | + IPHETH_USBINTF_PROTO) }, | |
11407 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11408 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, | |
11409 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11410 | + IPHETH_USBINTF_PROTO) }, | |
11411 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11412 | + USB_VENDOR_APPLE, USB_PRODUCT_IPAD, | |
11413 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11414 | + IPHETH_USBINTF_PROTO) }, | |
11415 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11416 | + USB_VENDOR_APPLE, USB_PRODUCT_IPAD_2, | |
11417 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11418 | + IPHETH_USBINTF_PROTO) }, | |
11419 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11420 | + USB_VENDOR_APPLE, USB_PRODUCT_IPAD_3, | |
11421 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11422 | + IPHETH_USBINTF_PROTO) }, | |
11423 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11424 | + USB_VENDOR_APPLE, USB_PRODUCT_IPAD_MINI, | |
11425 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11426 | + IPHETH_USBINTF_PROTO) }, | |
11427 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11428 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, | |
11429 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11430 | + IPHETH_USBINTF_PROTO) }, | |
11431 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11432 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S, | |
11433 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11434 | + IPHETH_USBINTF_PROTO) }, | |
11435 | + { USB_DEVICE_AND_INTERFACE_INFO( | |
11436 | + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_5, | |
11437 | + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, | |
11438 | + IPHETH_USBINTF_PROTO) }, | |
11439 | + { } | |
11440 | +}; | |
11441 | +MODULE_DEVICE_TABLE(usb, ipheth_table); | |
11442 | + | |
11443 | +struct ipheth_device { | |
11444 | + struct usb_device *udev; | |
11445 | + struct usb_interface *intf; | |
11446 | + struct net_device *net; | |
11447 | + struct sk_buff *tx_skb; | |
11448 | + struct urb *tx_urb; | |
11449 | + struct urb *rx_urb; | |
11450 | + unsigned char *tx_buf; | |
11451 | + unsigned char *rx_buf; | |
11452 | + unsigned char *ctrl_buf; | |
11453 | + u8 bulk_in; | |
11454 | + u8 bulk_out; | |
11455 | + struct delayed_work carrier_work; | |
11456 | +}; | |
11457 | + | |
11458 | +static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); | |
11459 | + | |
11460 | +static int ipheth_alloc_urbs(struct ipheth_device *iphone) | |
11461 | +{ | |
11462 | + struct urb *tx_urb = NULL; | |
11463 | + struct urb *rx_urb = NULL; | |
11464 | + u8 *tx_buf = NULL; | |
11465 | + u8 *rx_buf = NULL; | |
11466 | + | |
11467 | + tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
11468 | + if (tx_urb == NULL) | |
11469 | + goto error_nomem; | |
11470 | + | |
11471 | + rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
11472 | + if (rx_urb == NULL) | |
11473 | + goto free_tx_urb; | |
11474 | + | |
11475 | + tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, | |
11476 | + GFP_KERNEL, &tx_urb->transfer_dma); | |
11477 | + if (tx_buf == NULL) | |
11478 | + goto free_rx_urb; | |
11479 | + | |
11480 | + rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, | |
11481 | + GFP_KERNEL, &rx_urb->transfer_dma); | |
11482 | + if (rx_buf == NULL) | |
11483 | + goto free_tx_buf; | |
11484 | + | |
11485 | + | |
11486 | + iphone->tx_urb = tx_urb; | |
11487 | + iphone->rx_urb = rx_urb; | |
11488 | + iphone->tx_buf = tx_buf; | |
11489 | + iphone->rx_buf = rx_buf; | |
11490 | + return 0; | |
11491 | + | |
11492 | +free_tx_buf: | |
11493 | + usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf, | |
11494 | + tx_urb->transfer_dma); | |
11495 | +free_rx_urb: | |
11496 | + usb_free_urb(rx_urb); | |
11497 | +free_tx_urb: | |
11498 | + usb_free_urb(tx_urb); | |
11499 | +error_nomem: | |
11500 | + return -ENOMEM; | |
11501 | +} | |
11502 | + | |
11503 | +static void ipheth_free_urbs(struct ipheth_device *iphone) | |
11504 | +{ | |
11505 | + usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->rx_buf, | |
11506 | + iphone->rx_urb->transfer_dma); | |
11507 | + usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, | |
11508 | + iphone->tx_urb->transfer_dma); | |
11509 | + usb_free_urb(iphone->rx_urb); | |
11510 | + usb_free_urb(iphone->tx_urb); | |
11511 | +} | |
11512 | + | |
11513 | +static void ipheth_kill_urbs(struct ipheth_device *dev) | |
11514 | +{ | |
11515 | + usb_kill_urb(dev->tx_urb); | |
11516 | + usb_kill_urb(dev->rx_urb); | |
11517 | +} | |
11518 | + | |
11519 | +static void ipheth_rcvbulk_callback(struct urb *urb) | |
11520 | +{ | |
11521 | + struct ipheth_device *dev; | |
11522 | + struct sk_buff *skb; | |
11523 | + int status; | |
11524 | + char *buf; | |
11525 | + int len; | |
11526 | + | |
11527 | + dev = urb->context; | |
11528 | + if (dev == NULL) | |
11529 | + return; | |
11530 | + | |
11531 | + status = urb->status; | |
11532 | + switch (status) { | |
11533 | + case -ENOENT: | |
11534 | + case -ECONNRESET: | |
11535 | + case -ESHUTDOWN: | |
11536 | + return; | |
11537 | + case 0: | |
11538 | + break; | |
11539 | + default: | |
11540 | + dev_err(&dev->intf->dev, "%s: urb status: %d\n", | |
11541 | + __func__, status); | |
11542 | + return; | |
11543 | + } | |
11544 | + | |
11545 | + if (urb->actual_length <= IPHETH_IP_ALIGN) { | |
11546 | + dev->net->stats.rx_length_errors++; | |
11547 | + return; | |
11548 | + } | |
11549 | + len = urb->actual_length - IPHETH_IP_ALIGN; | |
11550 | + buf = urb->transfer_buffer + IPHETH_IP_ALIGN; | |
11551 | + | |
11552 | + skb = dev_alloc_skb(len); | |
11553 | + if (!skb) { | |
11554 | + dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", | |
11555 | + __func__); | |
11556 | + dev->net->stats.rx_dropped++; | |
11557 | + return; | |
11558 | + } | |
11559 | + | |
11560 | + memcpy(skb_put(skb, len), buf, len); | |
11561 | + skb->dev = dev->net; | |
11562 | + skb->protocol = eth_type_trans(skb, dev->net); | |
11563 | + | |
11564 | + dev->net->stats.rx_packets++; | |
11565 | + dev->net->stats.rx_bytes += len; | |
11566 | + | |
11567 | + netif_rx(skb); | |
11568 | + ipheth_rx_submit(dev, GFP_ATOMIC); | |
11569 | +} | |
11570 | + | |
11571 | +static void ipheth_sndbulk_callback(struct urb *urb) | |
11572 | +{ | |
11573 | + struct ipheth_device *dev; | |
11574 | + int status = urb->status; | |
11575 | + | |
11576 | + dev = urb->context; | |
11577 | + if (dev == NULL) | |
11578 | + return; | |
11579 | + | |
11580 | + if (status != 0 && | |
11581 | + status != -ENOENT && | |
11582 | + status != -ECONNRESET && | |
11583 | + status != -ESHUTDOWN) | |
11584 | + dev_err(&dev->intf->dev, "%s: urb status: %d\n", | |
11585 | + __func__, status); | |
11586 | + | |
11587 | + dev_kfree_skb_irq(dev->tx_skb); | |
11588 | + netif_wake_queue(dev->net); | |
11589 | +} | |
11590 | + | |
11591 | +static int ipheth_carrier_set(struct ipheth_device *dev) | |
11592 | +{ | |
11593 | + struct usb_device *udev = dev->udev; | |
11594 | + int retval; | |
11595 | + | |
11596 | + retval = usb_control_msg(udev, | |
11597 | + usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), | |
11598 | + IPHETH_CMD_CARRIER_CHECK, /* request */ | |
11599 | + 0xc0, /* request type */ | |
11600 | + 0x00, /* value */ | |
11601 | + 0x02, /* index */ | |
11602 | + dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, | |
11603 | + IPHETH_CTRL_TIMEOUT); | |
11604 | + if (retval < 0) { | |
11605 | + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", | |
11606 | + __func__, retval); | |
11607 | + return retval; | |
11608 | + } | |
11609 | + | |
11610 | + if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) | |
11611 | + netif_carrier_on(dev->net); | |
11612 | + else | |
11613 | + netif_carrier_off(dev->net); | |
11614 | + | |
11615 | + return 0; | |
11616 | +} | |
11617 | + | |
11618 | +static void ipheth_carrier_check_work(struct work_struct *work) | |
11619 | +{ | |
11620 | + struct ipheth_device *dev = container_of(work, struct ipheth_device, | |
11621 | + carrier_work.work); | |
11622 | + | |
11623 | + ipheth_carrier_set(dev); | |
11624 | + schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); | |
11625 | +} | |
11626 | + | |
11627 | +static int ipheth_get_macaddr(struct ipheth_device *dev) | |
11628 | +{ | |
11629 | + struct usb_device *udev = dev->udev; | |
11630 | + struct net_device *net = dev->net; | |
11631 | + int retval; | |
11632 | + | |
11633 | + retval = usb_control_msg(udev, | |
11634 | + usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), | |
11635 | + IPHETH_CMD_GET_MACADDR, /* request */ | |
11636 | + 0xc0, /* request type */ | |
11637 | + 0x00, /* value */ | |
11638 | + 0x02, /* index */ | |
11639 | + dev->ctrl_buf, | |
11640 | + IPHETH_CTRL_BUF_SIZE, | |
11641 | + IPHETH_CTRL_TIMEOUT); | |
11642 | + if (retval < 0) { | |
11643 | + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", | |
11644 | + __func__, retval); | |
11645 | + } else if (retval < ETH_ALEN) { | |
11646 | + dev_err(&dev->intf->dev, | |
11647 | + "%s: usb_control_msg: short packet: %d bytes\n", | |
11648 | + __func__, retval); | |
11649 | + retval = -EINVAL; | |
11650 | + } else { | |
11651 | + memcpy(net->dev_addr, dev->ctrl_buf, ETH_ALEN); | |
11652 | + retval = 0; | |
11653 | + } | |
11654 | + | |
11655 | + return retval; | |
11656 | +} | |
11657 | + | |
11658 | +static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) | |
11659 | +{ | |
11660 | + struct usb_device *udev = dev->udev; | |
11661 | + int retval; | |
11662 | + | |
11663 | + usb_fill_bulk_urb(dev->rx_urb, udev, | |
11664 | + usb_rcvbulkpipe(udev, dev->bulk_in), | |
11665 | + dev->rx_buf, IPHETH_BUF_SIZE, | |
11666 | + ipheth_rcvbulk_callback, | |
11667 | + dev); | |
11668 | + dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
11669 | + | |
11670 | + retval = usb_submit_urb(dev->rx_urb, mem_flags); | |
11671 | + if (retval) | |
11672 | + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", | |
11673 | + __func__, retval); | |
11674 | + return retval; | |
11675 | +} | |
11676 | + | |
11677 | +static int ipheth_open(struct net_device *net) | |
11678 | +{ | |
11679 | + struct ipheth_device *dev = netdev_priv(net); | |
11680 | + struct usb_device *udev = dev->udev; | |
11681 | + int retval = 0; | |
11682 | + | |
11683 | + usb_set_interface(udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM); | |
11684 | + | |
11685 | + retval = ipheth_carrier_set(dev); | |
11686 | + if (retval) | |
11687 | + return retval; | |
11688 | + | |
11689 | + retval = ipheth_rx_submit(dev, GFP_KERNEL); | |
11690 | + if (retval) | |
11691 | + return retval; | |
11692 | + | |
11693 | + schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); | |
11694 | + netif_start_queue(net); | |
11695 | + return retval; | |
11696 | +} | |
11697 | + | |
11698 | +static int ipheth_close(struct net_device *net) | |
11699 | +{ | |
11700 | + struct ipheth_device *dev = netdev_priv(net); | |
11701 | + | |
11702 | + cancel_delayed_work_sync(&dev->carrier_work); | |
11703 | + netif_stop_queue(net); | |
11704 | + return 0; | |
11705 | +} | |
11706 | + | |
11707 | +static int ipheth_tx(struct sk_buff *skb, struct net_device *net) | |
11708 | +{ | |
11709 | + struct ipheth_device *dev = netdev_priv(net); | |
11710 | + struct usb_device *udev = dev->udev; | |
11711 | + int retval; | |
11712 | + | |
11713 | + /* Paranoid */ | |
11714 | + if (skb->len > IPHETH_BUF_SIZE) { | |
11715 | + WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); | |
11716 | + dev->net->stats.tx_dropped++; | |
11717 | + dev_kfree_skb_irq(skb); | |
11718 | + return NETDEV_TX_OK; | |
11719 | + } | |
11720 | + | |
11721 | + memcpy(dev->tx_buf, skb->data, skb->len); | |
11722 | + if (skb->len < IPHETH_BUF_SIZE) | |
11723 | + memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); | |
11724 | + | |
11725 | + usb_fill_bulk_urb(dev->tx_urb, udev, | |
11726 | + usb_sndbulkpipe(udev, dev->bulk_out), | |
11727 | + dev->tx_buf, IPHETH_BUF_SIZE, | |
11728 | + ipheth_sndbulk_callback, | |
11729 | + dev); | |
11730 | + dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
11731 | + | |
11732 | + retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); | |
11733 | + if (retval) { | |
11734 | + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", | |
11735 | + __func__, retval); | |
11736 | + dev->net->stats.tx_errors++; | |
11737 | + dev_kfree_skb_irq(skb); | |
11738 | + } else { | |
11739 | + dev->tx_skb = skb; | |
11740 | + | |
11741 | + dev->net->stats.tx_packets++; | |
11742 | + dev->net->stats.tx_bytes += skb->len; | |
11743 | + netif_stop_queue(net); | |
11744 | + } | |
11745 | + | |
11746 | + return NETDEV_TX_OK; | |
11747 | +} | |
11748 | + | |
11749 | +static void ipheth_tx_timeout(struct net_device *net) | |
11750 | +{ | |
11751 | + struct ipheth_device *dev = netdev_priv(net); | |
11752 | + | |
11753 | + dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__); | |
11754 | + dev->net->stats.tx_errors++; | |
11755 | + usb_unlink_urb(dev->tx_urb); | |
11756 | +} | |
11757 | + | |
11758 | +static u32 ipheth_ethtool_op_get_link(struct net_device *net) | |
11759 | +{ | |
11760 | + struct ipheth_device *dev = netdev_priv(net); | |
11761 | + return netif_carrier_ok(dev->net); | |
11762 | +} | |
11763 | + | |
11764 | +static const struct ethtool_ops ops = { | |
11765 | + .get_link = ipheth_ethtool_op_get_link | |
11766 | +}; | |
11767 | + | |
11768 | +static const struct net_device_ops ipheth_netdev_ops = { | |
11769 | + .ndo_open = ipheth_open, | |
11770 | + .ndo_stop = ipheth_close, | |
11771 | + .ndo_start_xmit = ipheth_tx, | |
11772 | + .ndo_tx_timeout = ipheth_tx_timeout, | |
11773 | +}; | |
11774 | + | |
11775 | +static int ipheth_probe(struct usb_interface *intf, | |
11776 | + const struct usb_device_id *id) | |
11777 | +{ | |
11778 | + struct usb_device *udev = interface_to_usbdev(intf); | |
11779 | + struct usb_host_interface *hintf; | |
11780 | + struct usb_endpoint_descriptor *endp; | |
11781 | + struct ipheth_device *dev; | |
11782 | + struct net_device *netdev; | |
11783 | + int i; | |
11784 | + int retval; | |
11785 | + | |
11786 | + netdev = alloc_etherdev(sizeof(struct ipheth_device)); | |
11787 | + if (!netdev) | |
11788 | + return -ENOMEM; | |
11789 | + | |
11790 | + netdev->netdev_ops = &ipheth_netdev_ops; | |
11791 | + netdev->watchdog_timeo = IPHETH_TX_TIMEOUT; | |
11792 | + strcpy(netdev->name, "eth%d"); | |
11793 | + | |
11794 | + dev = netdev_priv(netdev); | |
11795 | + dev->udev = udev; | |
11796 | + dev->net = netdev; | |
11797 | + dev->intf = intf; | |
11798 | + | |
11799 | + /* Set up endpoints */ | |
11800 | + hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); | |
11801 | + if (hintf == NULL) { | |
11802 | + retval = -ENODEV; | |
11803 | + dev_err(&intf->dev, "Unable to find alternate settings interface\n"); | |
11804 | + goto err_endpoints; | |
11805 | + } | |
11806 | + | |
11807 | + for (i = 0; i < hintf->desc.bNumEndpoints; i++) { | |
11808 | + endp = &hintf->endpoint[i].desc; | |
11809 | + if (usb_endpoint_is_bulk_in(endp)) | |
11810 | + dev->bulk_in = endp->bEndpointAddress; | |
11811 | + else if (usb_endpoint_is_bulk_out(endp)) | |
11812 | + dev->bulk_out = endp->bEndpointAddress; | |
11813 | + } | |
11814 | + if (!(dev->bulk_in && dev->bulk_out)) { | |
11815 | + retval = -ENODEV; | |
11816 | + dev_err(&intf->dev, "Unable to find endpoints\n"); | |
11817 | + goto err_endpoints; | |
11818 | + } | |
11819 | + | |
11820 | + dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL); | |
11821 | + if (dev->ctrl_buf == NULL) { | |
11822 | + retval = -ENOMEM; | |
11823 | + goto err_alloc_ctrl_buf; | |
11824 | + } | |
11825 | + | |
11826 | + retval = ipheth_get_macaddr(dev); | |
11827 | + if (retval) | |
11828 | + goto err_get_macaddr; | |
11829 | + | |
11830 | + INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); | |
11831 | + | |
11832 | + retval = ipheth_alloc_urbs(dev); | |
11833 | + if (retval) { | |
11834 | + dev_err(&intf->dev, "error allocating urbs: %d\n", retval); | |
11835 | + goto err_alloc_urbs; | |
11836 | + } | |
11837 | + | |
11838 | + usb_set_intfdata(intf, dev); | |
11839 | + | |
11840 | + SET_NETDEV_DEV(netdev, &intf->dev); | |
11841 | + netdev->ethtool_ops = &ops; | |
11842 | + | |
11843 | + retval = register_netdev(netdev); | |
11844 | + if (retval) { | |
11845 | + dev_err(&intf->dev, "error registering netdev: %d\n", retval); | |
11846 | + retval = -EIO; | |
11847 | + goto err_register_netdev; | |
11848 | + } | |
11849 | + | |
11850 | + dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n"); | |
11851 | + return 0; | |
11852 | + | |
11853 | +err_register_netdev: | |
11854 | + ipheth_free_urbs(dev); | |
11855 | +err_alloc_urbs: | |
11856 | +err_get_macaddr: | |
11857 | +err_alloc_ctrl_buf: | |
11858 | + kfree(dev->ctrl_buf); | |
11859 | +err_endpoints: | |
11860 | + free_netdev(netdev); | |
11861 | + return retval; | |
11862 | +} | |
11863 | + | |
11864 | +static void ipheth_disconnect(struct usb_interface *intf) | |
11865 | +{ | |
11866 | + struct ipheth_device *dev; | |
11867 | + | |
11868 | + dev = usb_get_intfdata(intf); | |
11869 | + if (dev != NULL) { | |
11870 | + unregister_netdev(dev->net); | |
11871 | + ipheth_kill_urbs(dev); | |
11872 | + ipheth_free_urbs(dev); | |
11873 | + kfree(dev->ctrl_buf); | |
11874 | + free_netdev(dev->net); | |
11875 | + } | |
11876 | + usb_set_intfdata(intf, NULL); | |
11877 | + dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n"); | |
11878 | +} | |
11879 | + | |
11880 | +static struct usb_driver ipheth_driver = { | |
11881 | + .name = "ipheth", | |
11882 | + .probe = ipheth_probe, | |
11883 | + .disconnect = ipheth_disconnect, | |
11884 | + .id_table = ipheth_table, | |
11885 | + .disable_hub_initiated_lpm = 1, | |
11886 | +}; | |
11887 | + | |
11888 | +module_usb_driver(ipheth_driver); | |
11889 | + | |
11890 | +MODULE_AUTHOR("Diego Giagio <diego@giagio.com>"); | |
11891 | +MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver"); | |
11892 | +MODULE_LICENSE("Dual BSD/GPL"); | |
11893 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/kalmia.c backports-3.18.1-1/drivers/net/usb/kalmia.c | |
11894 | --- backports-3.18.1-1.org/drivers/net/usb/kalmia.c 1970-01-01 01:00:00.000000000 +0100 | |
11895 | +++ backports-3.18.1-1/drivers/net/usb/kalmia.c 2014-12-16 18:39:45.000000000 +0100 | |
11896 | @@ -0,0 +1,366 @@ | |
11897 | +/* | |
11898 | + * USB network interface driver for Samsung Kalmia based LTE USB modem like the | |
11899 | + * Samsung GT-B3730 and GT-B3710. | |
11900 | + * | |
11901 | + * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> | |
11902 | + * | |
11903 | + * Sponsored by Quicklink Video Distribution Services Ltd. | |
11904 | + * | |
11905 | + * Based on the cdc_eem module. | |
11906 | + * | |
11907 | + * This program is free software; you can redistribute it and/or modify | |
11908 | + * it under the terms of the GNU General Public License as published by | |
11909 | + * the Free Software Foundation; either version 2 of the License, or | |
11910 | + * (at your option) any later version. | |
11911 | + */ | |
11912 | + | |
11913 | +#include <linux/module.h> | |
11914 | +#include <linux/netdevice.h> | |
11915 | +#include <linux/etherdevice.h> | |
11916 | +#include <linux/ctype.h> | |
11917 | +#include <linux/ethtool.h> | |
11918 | +#include <linux/workqueue.h> | |
11919 | +#include <linux/mii.h> | |
11920 | +#include <linux/usb.h> | |
11921 | +#include <linux/crc32.h> | |
11922 | +#include <linux/usb/cdc.h> | |
11923 | +#include <linux/usb/usbnet.h> | |
11924 | +#include <linux/gfp.h> | |
11925 | + | |
11926 | +/* | |
11927 | + * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control | |
11928 | + * handled by the "option" module and an ethernet data port handled by this | |
11929 | + * module. | |
11930 | + * | |
11931 | + * The stick must first be switched into modem mode by usb_modeswitch | |
11932 | + * or similar tool. Then the modem gets sent two initialization packets by | |
11933 | + * this module, which gives the MAC address of the device. User space can then | |
11934 | + * connect the modem using AT commands through the ACM port and then use | |
11935 | + * DHCP on the network interface exposed by this module. Network packets are | |
11936 | + * sent to and from the modem in a proprietary format discovered after watching | |
11937 | + * the behavior of the windows driver for the modem. | |
11938 | + * | |
11939 | + * More information about the use of the modem is available in usb_modeswitch | |
11940 | + * forum and the project page: | |
11941 | + * | |
11942 | + * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 | |
11943 | + * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver | |
11944 | + */ | |
11945 | + | |
11946 | +/* #define DEBUG */ | |
11947 | +/* #define VERBOSE */ | |
11948 | + | |
11949 | +#define KALMIA_HEADER_LENGTH 6 | |
11950 | +#define KALMIA_ALIGN_SIZE 4 | |
11951 | +#define KALMIA_USB_TIMEOUT 10000 | |
11952 | + | |
11953 | +/*-------------------------------------------------------------------------*/ | |
11954 | + | |
11955 | +static int | |
11956 | +kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, | |
11957 | + u8 *buffer, u8 expected_len) | |
11958 | +{ | |
11959 | + int act_len; | |
11960 | + int status; | |
11961 | + | |
11962 | + netdev_dbg(dev->net, "Sending init packet"); | |
11963 | + | |
11964 | + status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), | |
11965 | + init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); | |
11966 | + if (status != 0) { | |
11967 | + netdev_err(dev->net, | |
11968 | + "Error sending init packet. Status %i, length %i\n", | |
11969 | + status, act_len); | |
11970 | + return status; | |
11971 | + } | |
11972 | + else if (act_len != init_msg_len) { | |
11973 | + netdev_err(dev->net, | |
11974 | + "Did not send all of init packet. Bytes sent: %i", | |
11975 | + act_len); | |
11976 | + } | |
11977 | + else { | |
11978 | + netdev_dbg(dev->net, "Successfully sent init packet."); | |
11979 | + } | |
11980 | + | |
11981 | + status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), | |
11982 | + buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); | |
11983 | + | |
11984 | + if (status != 0) | |
11985 | + netdev_err(dev->net, | |
11986 | + "Error receiving init result. Status %i, length %i\n", | |
11987 | + status, act_len); | |
11988 | + else if (act_len != expected_len) | |
11989 | + netdev_err(dev->net, "Unexpected init result length: %i\n", | |
11990 | + act_len); | |
11991 | + | |
11992 | + return status; | |
11993 | +} | |
11994 | + | |
11995 | +static int | |
11996 | +kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) | |
11997 | +{ | |
11998 | + static const char init_msg_1[] = | |
11999 | + { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, | |
12000 | + 0x00, 0x00 }; | |
12001 | + static const char init_msg_2[] = | |
12002 | + { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, | |
12003 | + 0x00, 0x00 }; | |
12004 | + static const int buflen = 28; | |
12005 | + char *usb_buf; | |
12006 | + int status; | |
12007 | + | |
12008 | + usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL); | |
12009 | + if (!usb_buf) | |
12010 | + return -ENOMEM; | |
12011 | + | |
12012 | + memcpy(usb_buf, init_msg_1, 12); | |
12013 | + status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1) | |
12014 | + / sizeof(init_msg_1[0]), usb_buf, 24); | |
12015 | + if (status != 0) | |
12016 | + return status; | |
12017 | + | |
12018 | + memcpy(usb_buf, init_msg_2, 12); | |
12019 | + status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2) | |
12020 | + / sizeof(init_msg_2[0]), usb_buf, 28); | |
12021 | + if (status != 0) | |
12022 | + return status; | |
12023 | + | |
12024 | + memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN); | |
12025 | + | |
12026 | + kfree(usb_buf); | |
12027 | + return status; | |
12028 | +} | |
12029 | + | |
12030 | +static int | |
12031 | +kalmia_bind(struct usbnet *dev, struct usb_interface *intf) | |
12032 | +{ | |
12033 | + int status; | |
12034 | + u8 ethernet_addr[ETH_ALEN]; | |
12035 | + | |
12036 | + /* Don't bind to AT command interface */ | |
12037 | + if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) | |
12038 | + return -EINVAL; | |
12039 | + | |
12040 | + dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); | |
12041 | + dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); | |
12042 | + dev->status = NULL; | |
12043 | + | |
12044 | + dev->net->hard_header_len += KALMIA_HEADER_LENGTH; | |
12045 | + dev->hard_mtu = 1400; | |
12046 | + dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing | |
12047 | + | |
12048 | + status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); | |
12049 | + | |
12050 | + if (status < 0) { | |
12051 | + usb_set_intfdata(intf, NULL); | |
12052 | + usb_driver_release_interface(driver_of(intf), intf); | |
12053 | + return status; | |
12054 | + } | |
12055 | + | |
12056 | + memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); | |
12057 | + | |
12058 | + return status; | |
12059 | +} | |
12060 | + | |
12061 | +static struct sk_buff * | |
12062 | +kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |
12063 | +{ | |
12064 | + struct sk_buff *skb2 = NULL; | |
12065 | + u16 content_len; | |
12066 | + unsigned char *header_start; | |
12067 | + unsigned char ether_type_1, ether_type_2; | |
12068 | + u8 remainder, padlen = 0; | |
12069 | + | |
12070 | + if (!skb_cloned(skb)) { | |
12071 | + int headroom = skb_headroom(skb); | |
12072 | + int tailroom = skb_tailroom(skb); | |
12073 | + | |
12074 | + if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom | |
12075 | + >= KALMIA_HEADER_LENGTH)) | |
12076 | + goto done; | |
12077 | + | |
12078 | + if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH | |
12079 | + + KALMIA_ALIGN_SIZE)) { | |
12080 | + skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, | |
12081 | + skb->data, skb->len); | |
12082 | + skb_set_tail_pointer(skb, skb->len); | |
12083 | + goto done; | |
12084 | + } | |
12085 | + } | |
12086 | + | |
12087 | + skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, | |
12088 | + KALMIA_ALIGN_SIZE, flags); | |
12089 | + if (!skb2) | |
12090 | + return NULL; | |
12091 | + | |
12092 | + dev_kfree_skb_any(skb); | |
12093 | + skb = skb2; | |
12094 | + | |
12095 | +done: | |
12096 | + header_start = skb_push(skb, KALMIA_HEADER_LENGTH); | |
12097 | + ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; | |
12098 | + ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; | |
12099 | + | |
12100 | + netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, | |
12101 | + ether_type_2); | |
12102 | + | |
12103 | + /* According to empiric data for data packages */ | |
12104 | + header_start[0] = 0x57; | |
12105 | + header_start[1] = 0x44; | |
12106 | + content_len = skb->len - KALMIA_HEADER_LENGTH; | |
12107 | + | |
12108 | + put_unaligned_le16(content_len, &header_start[2]); | |
12109 | + header_start[4] = ether_type_1; | |
12110 | + header_start[5] = ether_type_2; | |
12111 | + | |
12112 | + /* Align to 4 bytes by padding with zeros */ | |
12113 | + remainder = skb->len % KALMIA_ALIGN_SIZE; | |
12114 | + if (remainder > 0) { | |
12115 | + padlen = KALMIA_ALIGN_SIZE - remainder; | |
12116 | + memset(skb_put(skb, padlen), 0, padlen); | |
12117 | + } | |
12118 | + | |
12119 | + netdev_dbg(dev->net, | |
12120 | + "Sending package with length %i and padding %i. Header: %6phC.", | |
12121 | + content_len, padlen, header_start); | |
12122 | + | |
12123 | + return skb; | |
12124 | +} | |
12125 | + | |
12126 | +static int | |
12127 | +kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
12128 | +{ | |
12129 | + /* | |
12130 | + * Our task here is to strip off framing, leaving skb with one | |
12131 | + * data frame for the usbnet framework code to process. | |
12132 | + */ | |
12133 | + static const u8 HEADER_END_OF_USB_PACKET[] = | |
12134 | + { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; | |
12135 | + static const u8 EXPECTED_UNKNOWN_HEADER_1[] = | |
12136 | + { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; | |
12137 | + static const u8 EXPECTED_UNKNOWN_HEADER_2[] = | |
12138 | + { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; | |
12139 | + int i = 0; | |
12140 | + | |
12141 | + /* incomplete header? */ | |
12142 | + if (skb->len < KALMIA_HEADER_LENGTH) | |
12143 | + return 0; | |
12144 | + | |
12145 | + do { | |
12146 | + struct sk_buff *skb2 = NULL; | |
12147 | + u8 *header_start; | |
12148 | + u16 usb_packet_length, ether_packet_length; | |
12149 | + int is_last; | |
12150 | + | |
12151 | + header_start = skb->data; | |
12152 | + | |
12153 | + if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { | |
12154 | + if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, | |
12155 | + sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( | |
12156 | + header_start, EXPECTED_UNKNOWN_HEADER_2, | |
12157 | + sizeof(EXPECTED_UNKNOWN_HEADER_2))) { | |
12158 | + netdev_dbg(dev->net, | |
12159 | + "Received expected unknown frame header: %6phC. Package length: %i\n", | |
12160 | + header_start, | |
12161 | + skb->len - KALMIA_HEADER_LENGTH); | |
12162 | + } | |
12163 | + else { | |
12164 | + netdev_err(dev->net, | |
12165 | + "Received unknown frame header: %6phC. Package length: %i\n", | |
12166 | + header_start, | |
12167 | + skb->len - KALMIA_HEADER_LENGTH); | |
12168 | + return 0; | |
12169 | + } | |
12170 | + } | |
12171 | + else | |
12172 | + netdev_dbg(dev->net, | |
12173 | + "Received header: %6phC. Package length: %i\n", | |
12174 | + header_start, skb->len - KALMIA_HEADER_LENGTH); | |
12175 | + | |
12176 | + /* subtract start header and end header */ | |
12177 | + usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); | |
12178 | + ether_packet_length = get_unaligned_le16(&header_start[2]); | |
12179 | + skb_pull(skb, KALMIA_HEADER_LENGTH); | |
12180 | + | |
12181 | + /* Some small packets misses end marker */ | |
12182 | + if (usb_packet_length < ether_packet_length) { | |
12183 | + ether_packet_length = usb_packet_length | |
12184 | + + KALMIA_HEADER_LENGTH; | |
12185 | + is_last = true; | |
12186 | + } | |
12187 | + else { | |
12188 | + netdev_dbg(dev->net, "Correct package length #%i", i | |
12189 | + + 1); | |
12190 | + | |
12191 | + is_last = (memcmp(skb->data + ether_packet_length, | |
12192 | + HEADER_END_OF_USB_PACKET, | |
12193 | + sizeof(HEADER_END_OF_USB_PACKET)) == 0); | |
12194 | + if (!is_last) { | |
12195 | + header_start = skb->data + ether_packet_length; | |
12196 | + netdev_dbg(dev->net, | |
12197 | + "End header: %6phC. Package length: %i\n", | |
12198 | + header_start, | |
12199 | + skb->len - KALMIA_HEADER_LENGTH); | |
12200 | + } | |
12201 | + } | |
12202 | + | |
12203 | + if (is_last) { | |
12204 | + skb2 = skb; | |
12205 | + } | |
12206 | + else { | |
12207 | + skb2 = skb_clone(skb, GFP_ATOMIC); | |
12208 | + if (unlikely(!skb2)) | |
12209 | + return 0; | |
12210 | + } | |
12211 | + | |
12212 | + skb_trim(skb2, ether_packet_length); | |
12213 | + | |
12214 | + if (is_last) { | |
12215 | + return 1; | |
12216 | + } | |
12217 | + else { | |
12218 | + usbnet_skb_return(dev, skb2); | |
12219 | + skb_pull(skb, ether_packet_length); | |
12220 | + } | |
12221 | + | |
12222 | + i++; | |
12223 | + } | |
12224 | + while (skb->len); | |
12225 | + | |
12226 | + return 1; | |
12227 | +} | |
12228 | + | |
12229 | +static const struct driver_info kalmia_info = { | |
12230 | + .description = "Samsung Kalmia LTE USB dongle", | |
12231 | + .flags = FLAG_WWAN, | |
12232 | + .bind = kalmia_bind, | |
12233 | + .rx_fixup = kalmia_rx_fixup, | |
12234 | + .tx_fixup = kalmia_tx_fixup | |
12235 | +}; | |
12236 | + | |
12237 | +/*-------------------------------------------------------------------------*/ | |
12238 | + | |
12239 | +static const struct usb_device_id products[] = { | |
12240 | + /* The unswitched USB ID, to get the module auto loaded: */ | |
12241 | + { USB_DEVICE(0x04e8, 0x689a) }, | |
12242 | + /* The stick swithed into modem (by e.g. usb_modeswitch): */ | |
12243 | + { USB_DEVICE(0x04e8, 0x6889), | |
12244 | + .driver_info = (unsigned long) &kalmia_info, }, | |
12245 | + { /* EMPTY == end of list */} }; | |
12246 | +MODULE_DEVICE_TABLE( usb, products); | |
12247 | + | |
12248 | +static struct usb_driver kalmia_driver = { | |
12249 | + .name = "kalmia", | |
12250 | + .id_table = products, | |
12251 | + .probe = usbnet_probe, | |
12252 | + .disconnect = usbnet_disconnect, | |
12253 | + .suspend = usbnet_suspend, | |
12254 | + .resume = usbnet_resume, | |
12255 | + .disable_hub_initiated_lpm = 1, | |
12256 | +}; | |
12257 | + | |
12258 | +module_usb_driver(kalmia_driver); | |
12259 | + | |
12260 | +MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); | |
12261 | +MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); | |
12262 | +MODULE_LICENSE("GPL"); | |
12263 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/kaweth.c backports-3.18.1-1/drivers/net/usb/kaweth.c | |
12264 | --- backports-3.18.1-1.org/drivers/net/usb/kaweth.c 1970-01-01 01:00:00.000000000 +0100 | |
12265 | +++ backports-3.18.1-1/drivers/net/usb/kaweth.c 2014-12-16 18:39:45.000000000 +0100 | |
12266 | @@ -0,0 +1,1331 @@ | |
12267 | +/**************************************************************** | |
12268 | + * | |
12269 | + * kaweth.c - driver for KL5KUSB101 based USB->Ethernet | |
12270 | + * | |
12271 | + * (c) 2000 Interlan Communications | |
12272 | + * (c) 2000 Stephane Alnet | |
12273 | + * (C) 2001 Brad Hards | |
12274 | + * (C) 2002 Oliver Neukum | |
12275 | + * | |
12276 | + * Original author: The Zapman <zapman@interlan.net> | |
12277 | + * Inspired by, and much credit goes to Michael Rothwell | |
12278 | + * <rothwell@interlan.net> for the test equipment, help, and patience | |
12279 | + * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. | |
12280 | + * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki | |
12281 | + * for providing the firmware and driver resources. | |
12282 | + * | |
12283 | + * This program is free software; you can redistribute it and/or | |
12284 | + * modify it under the terms of the GNU General Public License as | |
12285 | + * published by the Free Software Foundation; either version 2, or | |
12286 | + * (at your option) any later version. | |
12287 | + * | |
12288 | + * This program is distributed in the hope that it will be useful, | |
12289 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12290 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12291 | + * GNU General Public License for more details. | |
12292 | + * | |
12293 | + * You should have received a copy of the GNU General Public License | |
12294 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
12295 | + * | |
12296 | + ****************************************************************/ | |
12297 | + | |
12298 | +/* TODO: | |
12299 | + * Develop test procedures for USB net interfaces | |
12300 | + * Run test procedures | |
12301 | + * Fix bugs from previous two steps | |
12302 | + * Snoop other OSs for any tricks we're not doing | |
12303 | + * Reduce arbitrary timeouts | |
12304 | + * Smart multicast support | |
12305 | + * Temporary MAC change support | |
12306 | + * Tunable SOFs parameter - ioctl()? | |
12307 | + * Ethernet stats collection | |
12308 | + * Code formatting improvements | |
12309 | + */ | |
12310 | + | |
12311 | +#include <linux/module.h> | |
12312 | +#include <linux/slab.h> | |
12313 | +#include <linux/string.h> | |
12314 | +#include <linux/delay.h> | |
12315 | +#include <linux/netdevice.h> | |
12316 | +#include <linux/etherdevice.h> | |
12317 | +#include <linux/usb.h> | |
12318 | +#include <linux/types.h> | |
12319 | +#include <linux/ethtool.h> | |
12320 | +#include <linux/dma-mapping.h> | |
12321 | +#include <linux/wait.h> | |
12322 | +#include <linux/firmware.h> | |
12323 | +#include <asm/uaccess.h> | |
12324 | +#include <asm/byteorder.h> | |
12325 | + | |
12326 | +#undef DEBUG | |
12327 | + | |
12328 | +#define KAWETH_MTU 1514 | |
12329 | +#define KAWETH_BUF_SIZE 1664 | |
12330 | +#define KAWETH_TX_TIMEOUT (5 * HZ) | |
12331 | +#define KAWETH_SCRATCH_SIZE 32 | |
12332 | +#define KAWETH_FIRMWARE_BUF_SIZE 4096 | |
12333 | +#define KAWETH_CONTROL_TIMEOUT (30000) | |
12334 | + | |
12335 | +#define KAWETH_STATUS_BROKEN 0x0000001 | |
12336 | +#define KAWETH_STATUS_CLOSING 0x0000002 | |
12337 | +#define KAWETH_STATUS_SUSPENDING 0x0000004 | |
12338 | + | |
12339 | +#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) | |
12340 | + | |
12341 | +#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 | |
12342 | +#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 | |
12343 | +#define KAWETH_PACKET_FILTER_DIRECTED 0x04 | |
12344 | +#define KAWETH_PACKET_FILTER_BROADCAST 0x08 | |
12345 | +#define KAWETH_PACKET_FILTER_MULTICAST 0x10 | |
12346 | + | |
12347 | +/* Table 7 */ | |
12348 | +#define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 | |
12349 | +#define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 | |
12350 | +#define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 | |
12351 | +#define KAWETH_COMMAND_STATISTICS 0x03 | |
12352 | +#define KAWETH_COMMAND_SET_TEMP_MAC 0x06 | |
12353 | +#define KAWETH_COMMAND_GET_TEMP_MAC 0x07 | |
12354 | +#define KAWETH_COMMAND_SET_URB_SIZE 0x08 | |
12355 | +#define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 | |
12356 | +#define KAWETH_COMMAND_SCAN 0xFF | |
12357 | + | |
12358 | +#define KAWETH_SOFS_TO_WAIT 0x05 | |
12359 | + | |
12360 | +#define INTBUFFERSIZE 4 | |
12361 | + | |
12362 | +#define STATE_OFFSET 0 | |
12363 | +#define STATE_MASK 0x40 | |
12364 | +#define STATE_SHIFT 5 | |
12365 | + | |
12366 | +#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) | |
12367 | + | |
12368 | + | |
12369 | +MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); | |
12370 | +MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); | |
12371 | +MODULE_LICENSE("GPL"); | |
12372 | +MODULE_FIRMWARE("kaweth/new_code.bin"); | |
12373 | +MODULE_FIRMWARE("kaweth/new_code_fix.bin"); | |
12374 | +MODULE_FIRMWARE("kaweth/trigger_code.bin"); | |
12375 | +MODULE_FIRMWARE("kaweth/trigger_code_fix.bin"); | |
12376 | + | |
12377 | +static const char driver_name[] = "kaweth"; | |
12378 | + | |
12379 | +static int kaweth_probe( | |
12380 | + struct usb_interface *intf, | |
12381 | + const struct usb_device_id *id /* from id_table */ | |
12382 | + ); | |
12383 | +static void kaweth_disconnect(struct usb_interface *intf); | |
12384 | +static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |
12385 | + unsigned int pipe, | |
12386 | + struct usb_ctrlrequest *cmd, void *data, | |
12387 | + int len, int timeout); | |
12388 | +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); | |
12389 | +static int kaweth_resume(struct usb_interface *intf); | |
12390 | + | |
12391 | +/**************************************************************** | |
12392 | + * usb_device_id | |
12393 | + ****************************************************************/ | |
12394 | +static struct usb_device_id usb_klsi_table[] = { | |
12395 | + { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ | |
12396 | + { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ | |
12397 | + { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ | |
12398 | + { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ | |
12399 | + { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ | |
12400 | + { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ | |
12401 | + { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ | |
12402 | + { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ | |
12403 | + { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ | |
12404 | + { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ | |
12405 | + { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ | |
12406 | + { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ | |
12407 | + { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ | |
12408 | + { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ | |
12409 | + { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ | |
12410 | + { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ | |
12411 | + { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ | |
12412 | + { USB_DEVICE(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */ | |
12413 | + { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ | |
12414 | + { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ | |
12415 | + { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ | |
12416 | + { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ | |
12417 | + { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ | |
12418 | + { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ | |
12419 | + { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ | |
12420 | + { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ | |
12421 | + { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ | |
12422 | + { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ | |
12423 | + { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ | |
12424 | + { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ | |
12425 | + { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ | |
12426 | + { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ | |
12427 | + { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ | |
12428 | + { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ | |
12429 | + { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ | |
12430 | + {} /* Null terminator */ | |
12431 | +}; | |
12432 | + | |
12433 | +MODULE_DEVICE_TABLE (usb, usb_klsi_table); | |
12434 | + | |
12435 | +/**************************************************************** | |
12436 | + * kaweth_driver | |
12437 | + ****************************************************************/ | |
12438 | +static struct usb_driver kaweth_driver = { | |
12439 | + .name = driver_name, | |
12440 | + .probe = kaweth_probe, | |
12441 | + .disconnect = kaweth_disconnect, | |
12442 | + .suspend = kaweth_suspend, | |
12443 | + .resume = kaweth_resume, | |
12444 | + .id_table = usb_klsi_table, | |
12445 | + .supports_autosuspend = 1, | |
12446 | + .disable_hub_initiated_lpm = 1, | |
12447 | +}; | |
12448 | + | |
12449 | +typedef __u8 eth_addr_t[6]; | |
12450 | + | |
12451 | +/**************************************************************** | |
12452 | + * usb_eth_dev | |
12453 | + ****************************************************************/ | |
12454 | +struct usb_eth_dev { | |
12455 | + char *name; | |
12456 | + __u16 vendor; | |
12457 | + __u16 device; | |
12458 | + void *pdata; | |
12459 | +}; | |
12460 | + | |
12461 | +/**************************************************************** | |
12462 | + * kaweth_ethernet_configuration | |
12463 | + * Refer Table 8 | |
12464 | + ****************************************************************/ | |
12465 | +struct kaweth_ethernet_configuration | |
12466 | +{ | |
12467 | + __u8 size; | |
12468 | + __u8 reserved1; | |
12469 | + __u8 reserved2; | |
12470 | + eth_addr_t hw_addr; | |
12471 | + __u32 statistics_mask; | |
12472 | + __le16 segment_size; | |
12473 | + __u16 max_multicast_filters; | |
12474 | + __u8 reserved3; | |
12475 | +} __packed; | |
12476 | + | |
12477 | +/**************************************************************** | |
12478 | + * kaweth_device | |
12479 | + ****************************************************************/ | |
12480 | +struct kaweth_device | |
12481 | +{ | |
12482 | + spinlock_t device_lock; | |
12483 | + | |
12484 | + __u32 status; | |
12485 | + int end; | |
12486 | + int suspend_lowmem_rx; | |
12487 | + int suspend_lowmem_ctrl; | |
12488 | + int linkstate; | |
12489 | + int opened; | |
12490 | + struct delayed_work lowmem_work; | |
12491 | + | |
12492 | + struct usb_device *dev; | |
12493 | + struct usb_interface *intf; | |
12494 | + struct net_device *net; | |
12495 | + wait_queue_head_t term_wait; | |
12496 | + | |
12497 | + struct urb *rx_urb; | |
12498 | + struct urb *tx_urb; | |
12499 | + struct urb *irq_urb; | |
12500 | + | |
12501 | + dma_addr_t intbufferhandle; | |
12502 | + __u8 *intbuffer; | |
12503 | + dma_addr_t rxbufferhandle; | |
12504 | + __u8 *rx_buf; | |
12505 | + | |
12506 | + | |
12507 | + struct sk_buff *tx_skb; | |
12508 | + | |
12509 | + __u8 *firmware_buf; | |
12510 | + __u8 scratch[KAWETH_SCRATCH_SIZE]; | |
12511 | + __u16 packet_filter_bitmap; | |
12512 | + | |
12513 | + struct kaweth_ethernet_configuration configuration; | |
12514 | + | |
12515 | + struct net_device_stats stats; | |
12516 | +}; | |
12517 | + | |
12518 | +/**************************************************************** | |
12519 | + * kaweth_control | |
12520 | + ****************************************************************/ | |
12521 | +static int kaweth_control(struct kaweth_device *kaweth, | |
12522 | + unsigned int pipe, | |
12523 | + __u8 request, | |
12524 | + __u8 requesttype, | |
12525 | + __u16 value, | |
12526 | + __u16 index, | |
12527 | + void *data, | |
12528 | + __u16 size, | |
12529 | + int timeout) | |
12530 | +{ | |
12531 | + struct usb_ctrlrequest *dr; | |
12532 | + int retval; | |
12533 | + | |
12534 | + netdev_dbg(kaweth->net, "kaweth_control()\n"); | |
12535 | + | |
12536 | + if(in_interrupt()) { | |
12537 | + netdev_dbg(kaweth->net, "in_interrupt()\n"); | |
12538 | + return -EBUSY; | |
12539 | + } | |
12540 | + | |
12541 | + dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | |
12542 | + if (!dr) | |
12543 | + return -ENOMEM; | |
12544 | + | |
12545 | + dr->bRequestType = requesttype; | |
12546 | + dr->bRequest = request; | |
12547 | + dr->wValue = cpu_to_le16(value); | |
12548 | + dr->wIndex = cpu_to_le16(index); | |
12549 | + dr->wLength = cpu_to_le16(size); | |
12550 | + | |
12551 | + retval = kaweth_internal_control_msg(kaweth->dev, | |
12552 | + pipe, | |
12553 | + dr, | |
12554 | + data, | |
12555 | + size, | |
12556 | + timeout); | |
12557 | + | |
12558 | + kfree(dr); | |
12559 | + return retval; | |
12560 | +} | |
12561 | + | |
12562 | +/**************************************************************** | |
12563 | + * kaweth_read_configuration | |
12564 | + ****************************************************************/ | |
12565 | +static int kaweth_read_configuration(struct kaweth_device *kaweth) | |
12566 | +{ | |
12567 | + int retval; | |
12568 | + | |
12569 | + netdev_dbg(kaweth->net, "Reading kaweth configuration\n"); | |
12570 | + | |
12571 | + retval = kaweth_control(kaweth, | |
12572 | + usb_rcvctrlpipe(kaweth->dev, 0), | |
12573 | + KAWETH_COMMAND_GET_ETHERNET_DESC, | |
12574 | + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, | |
12575 | + 0, | |
12576 | + 0, | |
12577 | + (void *)&kaweth->configuration, | |
12578 | + sizeof(kaweth->configuration), | |
12579 | + KAWETH_CONTROL_TIMEOUT); | |
12580 | + | |
12581 | + return retval; | |
12582 | +} | |
12583 | + | |
12584 | +/**************************************************************** | |
12585 | + * kaweth_set_urb_size | |
12586 | + ****************************************************************/ | |
12587 | +static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) | |
12588 | +{ | |
12589 | + int retval; | |
12590 | + | |
12591 | + netdev_dbg(kaweth->net, "Setting URB size to %d\n", (unsigned)urb_size); | |
12592 | + | |
12593 | + retval = kaweth_control(kaweth, | |
12594 | + usb_sndctrlpipe(kaweth->dev, 0), | |
12595 | + KAWETH_COMMAND_SET_URB_SIZE, | |
12596 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
12597 | + urb_size, | |
12598 | + 0, | |
12599 | + (void *)&kaweth->scratch, | |
12600 | + 0, | |
12601 | + KAWETH_CONTROL_TIMEOUT); | |
12602 | + | |
12603 | + return retval; | |
12604 | +} | |
12605 | + | |
12606 | +/**************************************************************** | |
12607 | + * kaweth_set_sofs_wait | |
12608 | + ****************************************************************/ | |
12609 | +static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) | |
12610 | +{ | |
12611 | + int retval; | |
12612 | + | |
12613 | + netdev_dbg(kaweth->net, "Set SOFS wait to %d\n", (unsigned)sofs_wait); | |
12614 | + | |
12615 | + retval = kaweth_control(kaweth, | |
12616 | + usb_sndctrlpipe(kaweth->dev, 0), | |
12617 | + KAWETH_COMMAND_SET_SOFS_WAIT, | |
12618 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
12619 | + sofs_wait, | |
12620 | + 0, | |
12621 | + (void *)&kaweth->scratch, | |
12622 | + 0, | |
12623 | + KAWETH_CONTROL_TIMEOUT); | |
12624 | + | |
12625 | + return retval; | |
12626 | +} | |
12627 | + | |
12628 | +/**************************************************************** | |
12629 | + * kaweth_set_receive_filter | |
12630 | + ****************************************************************/ | |
12631 | +static int kaweth_set_receive_filter(struct kaweth_device *kaweth, | |
12632 | + __u16 receive_filter) | |
12633 | +{ | |
12634 | + int retval; | |
12635 | + | |
12636 | + netdev_dbg(kaweth->net, "Set receive filter to %d\n", | |
12637 | + (unsigned)receive_filter); | |
12638 | + | |
12639 | + retval = kaweth_control(kaweth, | |
12640 | + usb_sndctrlpipe(kaweth->dev, 0), | |
12641 | + KAWETH_COMMAND_SET_PACKET_FILTER, | |
12642 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
12643 | + receive_filter, | |
12644 | + 0, | |
12645 | + (void *)&kaweth->scratch, | |
12646 | + 0, | |
12647 | + KAWETH_CONTROL_TIMEOUT); | |
12648 | + | |
12649 | + return retval; | |
12650 | +} | |
12651 | + | |
12652 | +/**************************************************************** | |
12653 | + * kaweth_download_firmware | |
12654 | + ****************************************************************/ | |
12655 | +static int kaweth_download_firmware(struct kaweth_device *kaweth, | |
12656 | + const char *fwname, | |
12657 | + __u8 interrupt, | |
12658 | + __u8 type) | |
12659 | +{ | |
12660 | + const struct firmware *fw; | |
12661 | + int data_len; | |
12662 | + int ret; | |
12663 | + | |
12664 | + ret = request_firmware(&fw, fwname, &kaweth->dev->dev); | |
12665 | + if (ret) { | |
12666 | + dev_err(&kaweth->intf->dev, "Firmware request failed\n"); | |
12667 | + return ret; | |
12668 | + } | |
12669 | + | |
12670 | + if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { | |
12671 | + dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n", | |
12672 | + fw->size); | |
12673 | + release_firmware(fw); | |
12674 | + return -ENOSPC; | |
12675 | + } | |
12676 | + data_len = fw->size; | |
12677 | + memcpy(kaweth->firmware_buf, fw->data, fw->size); | |
12678 | + | |
12679 | + release_firmware(fw); | |
12680 | + | |
12681 | + kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; | |
12682 | + kaweth->firmware_buf[3] = data_len >> 8; | |
12683 | + kaweth->firmware_buf[4] = type; | |
12684 | + kaweth->firmware_buf[5] = interrupt; | |
12685 | + | |
12686 | + netdev_dbg(kaweth->net, "High: %i, Low:%i\n", kaweth->firmware_buf[3], | |
12687 | + kaweth->firmware_buf[2]); | |
12688 | + | |
12689 | + netdev_dbg(kaweth->net, | |
12690 | + "Downloading firmware at %p to kaweth device at %p\n", | |
12691 | + kaweth->firmware_buf, kaweth); | |
12692 | + netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len); | |
12693 | + | |
12694 | + return kaweth_control(kaweth, | |
12695 | + usb_sndctrlpipe(kaweth->dev, 0), | |
12696 | + KAWETH_COMMAND_SCAN, | |
12697 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
12698 | + 0, | |
12699 | + 0, | |
12700 | + (void *)kaweth->firmware_buf, | |
12701 | + data_len, | |
12702 | + KAWETH_CONTROL_TIMEOUT); | |
12703 | +} | |
12704 | + | |
12705 | +/**************************************************************** | |
12706 | + * kaweth_trigger_firmware | |
12707 | + ****************************************************************/ | |
12708 | +static int kaweth_trigger_firmware(struct kaweth_device *kaweth, | |
12709 | + __u8 interrupt) | |
12710 | +{ | |
12711 | + kaweth->firmware_buf[0] = 0xB6; | |
12712 | + kaweth->firmware_buf[1] = 0xC3; | |
12713 | + kaweth->firmware_buf[2] = 0x01; | |
12714 | + kaweth->firmware_buf[3] = 0x00; | |
12715 | + kaweth->firmware_buf[4] = 0x06; | |
12716 | + kaweth->firmware_buf[5] = interrupt; | |
12717 | + kaweth->firmware_buf[6] = 0x00; | |
12718 | + kaweth->firmware_buf[7] = 0x00; | |
12719 | + | |
12720 | + netdev_dbg(kaweth->net, "Triggering firmware\n"); | |
12721 | + | |
12722 | + return kaweth_control(kaweth, | |
12723 | + usb_sndctrlpipe(kaweth->dev, 0), | |
12724 | + KAWETH_COMMAND_SCAN, | |
12725 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
12726 | + 0, | |
12727 | + 0, | |
12728 | + (void *)kaweth->firmware_buf, | |
12729 | + 8, | |
12730 | + KAWETH_CONTROL_TIMEOUT); | |
12731 | +} | |
12732 | + | |
12733 | +/**************************************************************** | |
12734 | + * kaweth_reset | |
12735 | + ****************************************************************/ | |
12736 | +static int kaweth_reset(struct kaweth_device *kaweth) | |
12737 | +{ | |
12738 | + int result; | |
12739 | + | |
12740 | + netdev_dbg(kaweth->net, "kaweth_reset(%p)\n", kaweth); | |
12741 | + result = usb_reset_configuration(kaweth->dev); | |
12742 | + mdelay(10); | |
12743 | + | |
12744 | + netdev_dbg(kaweth->net, "kaweth_reset() returns %d.\n", result); | |
12745 | + | |
12746 | + return result; | |
12747 | +} | |
12748 | + | |
12749 | +static void kaweth_usb_receive(struct urb *); | |
12750 | +static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); | |
12751 | + | |
12752 | +/**************************************************************** | |
12753 | + int_callback | |
12754 | +*****************************************************************/ | |
12755 | + | |
12756 | +static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) | |
12757 | +{ | |
12758 | + int status; | |
12759 | + | |
12760 | + status = usb_submit_urb (kaweth->irq_urb, mf); | |
12761 | + if (unlikely(status == -ENOMEM)) { | |
12762 | + kaweth->suspend_lowmem_ctrl = 1; | |
12763 | + schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | |
12764 | + } else { | |
12765 | + kaweth->suspend_lowmem_ctrl = 0; | |
12766 | + } | |
12767 | + | |
12768 | + if (status) | |
12769 | + dev_err(&kaweth->intf->dev, | |
12770 | + "can't resubmit intr, %s-%s, status %d\n", | |
12771 | + kaweth->dev->bus->bus_name, | |
12772 | + kaweth->dev->devpath, status); | |
12773 | +} | |
12774 | + | |
12775 | +static void int_callback(struct urb *u) | |
12776 | +{ | |
12777 | + struct kaweth_device *kaweth = u->context; | |
12778 | + int act_state; | |
12779 | + int status = u->status; | |
12780 | + | |
12781 | + switch (status) { | |
12782 | + case 0: /* success */ | |
12783 | + break; | |
12784 | + case -ECONNRESET: /* unlink */ | |
12785 | + case -ENOENT: | |
12786 | + case -ESHUTDOWN: | |
12787 | + return; | |
12788 | + /* -EPIPE: should clear the halt */ | |
12789 | + default: /* error */ | |
12790 | + goto resubmit; | |
12791 | + } | |
12792 | + | |
12793 | + /* we check the link state to report changes */ | |
12794 | + if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { | |
12795 | + if (act_state) | |
12796 | + netif_carrier_on(kaweth->net); | |
12797 | + else | |
12798 | + netif_carrier_off(kaweth->net); | |
12799 | + | |
12800 | + kaweth->linkstate = act_state; | |
12801 | + } | |
12802 | +resubmit: | |
12803 | + kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); | |
12804 | +} | |
12805 | + | |
12806 | +static void kaweth_resubmit_tl(struct work_struct *work) | |
12807 | +{ | |
12808 | + struct kaweth_device *kaweth = | |
12809 | + container_of(work, struct kaweth_device, lowmem_work.work); | |
12810 | + | |
12811 | + if (IS_BLOCKED(kaweth->status)) | |
12812 | + return; | |
12813 | + | |
12814 | + if (kaweth->suspend_lowmem_rx) | |
12815 | + kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | |
12816 | + | |
12817 | + if (kaweth->suspend_lowmem_ctrl) | |
12818 | + kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | |
12819 | +} | |
12820 | + | |
12821 | + | |
12822 | +/**************************************************************** | |
12823 | + * kaweth_resubmit_rx_urb | |
12824 | + ****************************************************************/ | |
12825 | +static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, | |
12826 | + gfp_t mem_flags) | |
12827 | +{ | |
12828 | + int result; | |
12829 | + | |
12830 | + usb_fill_bulk_urb(kaweth->rx_urb, | |
12831 | + kaweth->dev, | |
12832 | + usb_rcvbulkpipe(kaweth->dev, 1), | |
12833 | + kaweth->rx_buf, | |
12834 | + KAWETH_BUF_SIZE, | |
12835 | + kaweth_usb_receive, | |
12836 | + kaweth); | |
12837 | + kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
12838 | + kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; | |
12839 | + | |
12840 | + if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { | |
12841 | + if (result == -ENOMEM) { | |
12842 | + kaweth->suspend_lowmem_rx = 1; | |
12843 | + schedule_delayed_work(&kaweth->lowmem_work, HZ/4); | |
12844 | + } | |
12845 | + dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n", | |
12846 | + result); | |
12847 | + } else { | |
12848 | + kaweth->suspend_lowmem_rx = 0; | |
12849 | + } | |
12850 | + | |
12851 | + return result; | |
12852 | +} | |
12853 | + | |
12854 | +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); | |
12855 | + | |
12856 | +/**************************************************************** | |
12857 | + * kaweth_usb_receive | |
12858 | + ****************************************************************/ | |
12859 | +static void kaweth_usb_receive(struct urb *urb) | |
12860 | +{ | |
12861 | + struct device *dev = &urb->dev->dev; | |
12862 | + struct kaweth_device *kaweth = urb->context; | |
12863 | + struct net_device *net = kaweth->net; | |
12864 | + int status = urb->status; | |
12865 | + | |
12866 | + int count = urb->actual_length; | |
12867 | + int count2 = urb->transfer_buffer_length; | |
12868 | + | |
12869 | + __u16 pkt_len = le16_to_cpup((__le16 *)kaweth->rx_buf); | |
12870 | + | |
12871 | + struct sk_buff *skb; | |
12872 | + | |
12873 | + if (unlikely(status == -EPIPE)) { | |
12874 | + kaweth->stats.rx_errors++; | |
12875 | + kaweth->end = 1; | |
12876 | + wake_up(&kaweth->term_wait); | |
12877 | + dev_dbg(dev, "Status was -EPIPE.\n"); | |
12878 | + return; | |
12879 | + } | |
12880 | + if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { | |
12881 | + /* we are killed - set a flag and wake the disconnect handler */ | |
12882 | + kaweth->end = 1; | |
12883 | + wake_up(&kaweth->term_wait); | |
12884 | + dev_dbg(dev, "Status was -ECONNRESET or -ESHUTDOWN.\n"); | |
12885 | + return; | |
12886 | + } | |
12887 | + if (unlikely(status == -EPROTO || status == -ETIME || | |
12888 | + status == -EILSEQ)) { | |
12889 | + kaweth->stats.rx_errors++; | |
12890 | + dev_dbg(dev, "Status was -EPROTO, -ETIME, or -EILSEQ.\n"); | |
12891 | + return; | |
12892 | + } | |
12893 | + if (unlikely(status == -EOVERFLOW)) { | |
12894 | + kaweth->stats.rx_errors++; | |
12895 | + dev_dbg(dev, "Status was -EOVERFLOW.\n"); | |
12896 | + } | |
12897 | + spin_lock(&kaweth->device_lock); | |
12898 | + if (IS_BLOCKED(kaweth->status)) { | |
12899 | + spin_unlock(&kaweth->device_lock); | |
12900 | + return; | |
12901 | + } | |
12902 | + spin_unlock(&kaweth->device_lock); | |
12903 | + | |
12904 | + if(status && status != -EREMOTEIO && count != 1) { | |
12905 | + dev_err(&kaweth->intf->dev, | |
12906 | + "%s RX status: %d count: %d packet_len: %d\n", | |
12907 | + net->name, status, count, (int)pkt_len); | |
12908 | + kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | |
12909 | + return; | |
12910 | + } | |
12911 | + | |
12912 | + if(kaweth->net && (count > 2)) { | |
12913 | + if(pkt_len > (count - 2)) { | |
12914 | + dev_err(&kaweth->intf->dev, | |
12915 | + "Packet length too long for USB frame (pkt_len: %x, count: %x)\n", | |
12916 | + pkt_len, count); | |
12917 | + dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n", | |
12918 | + pkt_len & 2047); | |
12919 | + dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2); | |
12920 | + kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | |
12921 | + return; | |
12922 | + } | |
12923 | + | |
12924 | + if(!(skb = dev_alloc_skb(pkt_len+2))) { | |
12925 | + kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | |
12926 | + return; | |
12927 | + } | |
12928 | + | |
12929 | + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ | |
12930 | + | |
12931 | + skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len); | |
12932 | + | |
12933 | + skb_put(skb, pkt_len); | |
12934 | + | |
12935 | + skb->protocol = eth_type_trans(skb, net); | |
12936 | + | |
12937 | + netif_rx(skb); | |
12938 | + | |
12939 | + kaweth->stats.rx_packets++; | |
12940 | + kaweth->stats.rx_bytes += pkt_len; | |
12941 | + } | |
12942 | + | |
12943 | + kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); | |
12944 | +} | |
12945 | + | |
12946 | +/**************************************************************** | |
12947 | + * kaweth_open | |
12948 | + ****************************************************************/ | |
12949 | +static int kaweth_open(struct net_device *net) | |
12950 | +{ | |
12951 | + struct kaweth_device *kaweth = netdev_priv(net); | |
12952 | + int res; | |
12953 | + | |
12954 | + netdev_dbg(kaweth->net, "Opening network device.\n"); | |
12955 | + | |
12956 | + res = usb_autopm_get_interface(kaweth->intf); | |
12957 | + if (res) { | |
12958 | + dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n"); | |
12959 | + return -EIO; | |
12960 | + } | |
12961 | + res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); | |
12962 | + if (res) | |
12963 | + goto err_out; | |
12964 | + | |
12965 | + usb_fill_int_urb( | |
12966 | + kaweth->irq_urb, | |
12967 | + kaweth->dev, | |
12968 | + usb_rcvintpipe(kaweth->dev, 3), | |
12969 | + kaweth->intbuffer, | |
12970 | + INTBUFFERSIZE, | |
12971 | + int_callback, | |
12972 | + kaweth, | |
12973 | + 250); /* overriding the descriptor */ | |
12974 | + kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; | |
12975 | + kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | |
12976 | + | |
12977 | + res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); | |
12978 | + if (res) { | |
12979 | + usb_kill_urb(kaweth->rx_urb); | |
12980 | + goto err_out; | |
12981 | + } | |
12982 | + kaweth->opened = 1; | |
12983 | + | |
12984 | + netif_start_queue(net); | |
12985 | + | |
12986 | + kaweth_async_set_rx_mode(kaweth); | |
12987 | + return 0; | |
12988 | + | |
12989 | +err_out: | |
12990 | + usb_autopm_put_interface(kaweth->intf); | |
12991 | + return -EIO; | |
12992 | +} | |
12993 | + | |
12994 | +/**************************************************************** | |
12995 | + * kaweth_kill_urbs | |
12996 | + ****************************************************************/ | |
12997 | +static void kaweth_kill_urbs(struct kaweth_device *kaweth) | |
12998 | +{ | |
12999 | + usb_kill_urb(kaweth->irq_urb); | |
13000 | + usb_kill_urb(kaweth->rx_urb); | |
13001 | + usb_kill_urb(kaweth->tx_urb); | |
13002 | + | |
13003 | + cancel_delayed_work_sync(&kaweth->lowmem_work); | |
13004 | + | |
13005 | + /* a scheduled work may have resubmitted, | |
13006 | + we hit them again */ | |
13007 | + usb_kill_urb(kaweth->irq_urb); | |
13008 | + usb_kill_urb(kaweth->rx_urb); | |
13009 | +} | |
13010 | + | |
13011 | +/**************************************************************** | |
13012 | + * kaweth_close | |
13013 | + ****************************************************************/ | |
13014 | +static int kaweth_close(struct net_device *net) | |
13015 | +{ | |
13016 | + struct kaweth_device *kaweth = netdev_priv(net); | |
13017 | + | |
13018 | + netif_stop_queue(net); | |
13019 | + kaweth->opened = 0; | |
13020 | + | |
13021 | + kaweth->status |= KAWETH_STATUS_CLOSING; | |
13022 | + | |
13023 | + kaweth_kill_urbs(kaweth); | |
13024 | + | |
13025 | + kaweth->status &= ~KAWETH_STATUS_CLOSING; | |
13026 | + | |
13027 | + usb_autopm_put_interface(kaweth->intf); | |
13028 | + | |
13029 | + return 0; | |
13030 | +} | |
13031 | + | |
13032 | +static u32 kaweth_get_link(struct net_device *dev) | |
13033 | +{ | |
13034 | + struct kaweth_device *kaweth = netdev_priv(dev); | |
13035 | + | |
13036 | + return kaweth->linkstate; | |
13037 | +} | |
13038 | + | |
13039 | +static const struct ethtool_ops ops = { | |
13040 | + .get_link = kaweth_get_link | |
13041 | +}; | |
13042 | + | |
13043 | +/**************************************************************** | |
13044 | + * kaweth_usb_transmit_complete | |
13045 | + ****************************************************************/ | |
13046 | +static void kaweth_usb_transmit_complete(struct urb *urb) | |
13047 | +{ | |
13048 | + struct kaweth_device *kaweth = urb->context; | |
13049 | + struct sk_buff *skb = kaweth->tx_skb; | |
13050 | + int status = urb->status; | |
13051 | + | |
13052 | + if (unlikely(status != 0)) | |
13053 | + if (status != -ENOENT) | |
13054 | + dev_dbg(&urb->dev->dev, "%s: TX status %d.\n", | |
13055 | + kaweth->net->name, status); | |
13056 | + | |
13057 | + netif_wake_queue(kaweth->net); | |
13058 | + dev_kfree_skb_irq(skb); | |
13059 | +} | |
13060 | + | |
13061 | +/**************************************************************** | |
13062 | + * kaweth_start_xmit | |
13063 | + ****************************************************************/ | |
13064 | +static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, | |
13065 | + struct net_device *net) | |
13066 | +{ | |
13067 | + struct kaweth_device *kaweth = netdev_priv(net); | |
13068 | + __le16 *private_header; | |
13069 | + | |
13070 | + int res; | |
13071 | + | |
13072 | + spin_lock_irq(&kaweth->device_lock); | |
13073 | + | |
13074 | + kaweth_async_set_rx_mode(kaweth); | |
13075 | + netif_stop_queue(net); | |
13076 | + if (IS_BLOCKED(kaweth->status)) { | |
13077 | + goto skip; | |
13078 | + } | |
13079 | + | |
13080 | + /* We now decide whether we can put our special header into the sk_buff */ | |
13081 | + if (skb_cloned(skb) || skb_headroom(skb) < 2) { | |
13082 | + /* no such luck - we make our own */ | |
13083 | + struct sk_buff *copied_skb; | |
13084 | + copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); | |
13085 | + dev_kfree_skb_irq(skb); | |
13086 | + skb = copied_skb; | |
13087 | + if (!copied_skb) { | |
13088 | + kaweth->stats.tx_errors++; | |
13089 | + netif_start_queue(net); | |
13090 | + spin_unlock_irq(&kaweth->device_lock); | |
13091 | + return NETDEV_TX_OK; | |
13092 | + } | |
13093 | + } | |
13094 | + | |
13095 | + private_header = (__le16 *)__skb_push(skb, 2); | |
13096 | + *private_header = cpu_to_le16(skb->len-2); | |
13097 | + kaweth->tx_skb = skb; | |
13098 | + | |
13099 | + usb_fill_bulk_urb(kaweth->tx_urb, | |
13100 | + kaweth->dev, | |
13101 | + usb_sndbulkpipe(kaweth->dev, 2), | |
13102 | + private_header, | |
13103 | + skb->len, | |
13104 | + kaweth_usb_transmit_complete, | |
13105 | + kaweth); | |
13106 | + kaweth->end = 0; | |
13107 | + | |
13108 | + if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) | |
13109 | + { | |
13110 | + dev_warn(&net->dev, "kaweth failed tx_urb %d\n", res); | |
13111 | +skip: | |
13112 | + kaweth->stats.tx_errors++; | |
13113 | + | |
13114 | + netif_start_queue(net); | |
13115 | + dev_kfree_skb_irq(skb); | |
13116 | + } | |
13117 | + else | |
13118 | + { | |
13119 | + kaweth->stats.tx_packets++; | |
13120 | + kaweth->stats.tx_bytes += skb->len; | |
13121 | + } | |
13122 | + | |
13123 | + spin_unlock_irq(&kaweth->device_lock); | |
13124 | + | |
13125 | + return NETDEV_TX_OK; | |
13126 | +} | |
13127 | + | |
13128 | +/**************************************************************** | |
13129 | + * kaweth_set_rx_mode | |
13130 | + ****************************************************************/ | |
13131 | +static void kaweth_set_rx_mode(struct net_device *net) | |
13132 | +{ | |
13133 | + struct kaweth_device *kaweth = netdev_priv(net); | |
13134 | + | |
13135 | + __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | | |
13136 | + KAWETH_PACKET_FILTER_BROADCAST | | |
13137 | + KAWETH_PACKET_FILTER_MULTICAST; | |
13138 | + | |
13139 | + netdev_dbg(net, "Setting Rx mode to %d\n", packet_filter_bitmap); | |
13140 | + | |
13141 | + netif_stop_queue(net); | |
13142 | + | |
13143 | + if (net->flags & IFF_PROMISC) { | |
13144 | + packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; | |
13145 | + } | |
13146 | + else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { | |
13147 | + packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; | |
13148 | + } | |
13149 | + | |
13150 | + kaweth->packet_filter_bitmap = packet_filter_bitmap; | |
13151 | + netif_wake_queue(net); | |
13152 | +} | |
13153 | + | |
13154 | +/**************************************************************** | |
13155 | + * kaweth_async_set_rx_mode | |
13156 | + ****************************************************************/ | |
13157 | +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) | |
13158 | +{ | |
13159 | + int result; | |
13160 | + __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; | |
13161 | + | |
13162 | + kaweth->packet_filter_bitmap = 0; | |
13163 | + if (packet_filter_bitmap == 0) | |
13164 | + return; | |
13165 | + | |
13166 | + if (in_interrupt()) | |
13167 | + return; | |
13168 | + | |
13169 | + result = kaweth_control(kaweth, | |
13170 | + usb_sndctrlpipe(kaweth->dev, 0), | |
13171 | + KAWETH_COMMAND_SET_PACKET_FILTER, | |
13172 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | |
13173 | + packet_filter_bitmap, | |
13174 | + 0, | |
13175 | + (void *)&kaweth->scratch, | |
13176 | + 0, | |
13177 | + KAWETH_CONTROL_TIMEOUT); | |
13178 | + | |
13179 | + if(result < 0) { | |
13180 | + dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n", | |
13181 | + result); | |
13182 | + } | |
13183 | + else { | |
13184 | + netdev_dbg(kaweth->net, "Set Rx mode to %d\n", | |
13185 | + packet_filter_bitmap); | |
13186 | + } | |
13187 | +} | |
13188 | + | |
13189 | +/**************************************************************** | |
13190 | + * kaweth_netdev_stats | |
13191 | + ****************************************************************/ | |
13192 | +static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev) | |
13193 | +{ | |
13194 | + struct kaweth_device *kaweth = netdev_priv(dev); | |
13195 | + return &kaweth->stats; | |
13196 | +} | |
13197 | + | |
13198 | +/**************************************************************** | |
13199 | + * kaweth_tx_timeout | |
13200 | + ****************************************************************/ | |
13201 | +static void kaweth_tx_timeout(struct net_device *net) | |
13202 | +{ | |
13203 | + struct kaweth_device *kaweth = netdev_priv(net); | |
13204 | + | |
13205 | + dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n", net->name); | |
13206 | + kaweth->stats.tx_errors++; | |
13207 | + net->trans_start = jiffies; | |
13208 | + | |
13209 | + usb_unlink_urb(kaweth->tx_urb); | |
13210 | +} | |
13211 | + | |
13212 | +/**************************************************************** | |
13213 | + * kaweth_suspend | |
13214 | + ****************************************************************/ | |
13215 | +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) | |
13216 | +{ | |
13217 | + struct kaweth_device *kaweth = usb_get_intfdata(intf); | |
13218 | + unsigned long flags; | |
13219 | + | |
13220 | + dev_dbg(&intf->dev, "Suspending device\n"); | |
13221 | + spin_lock_irqsave(&kaweth->device_lock, flags); | |
13222 | + kaweth->status |= KAWETH_STATUS_SUSPENDING; | |
13223 | + spin_unlock_irqrestore(&kaweth->device_lock, flags); | |
13224 | + | |
13225 | + kaweth_kill_urbs(kaweth); | |
13226 | + return 0; | |
13227 | +} | |
13228 | + | |
13229 | +/**************************************************************** | |
13230 | + * kaweth_resume | |
13231 | + ****************************************************************/ | |
13232 | +static int kaweth_resume(struct usb_interface *intf) | |
13233 | +{ | |
13234 | + struct kaweth_device *kaweth = usb_get_intfdata(intf); | |
13235 | + unsigned long flags; | |
13236 | + | |
13237 | + dev_dbg(&intf->dev, "Resuming device\n"); | |
13238 | + spin_lock_irqsave(&kaweth->device_lock, flags); | |
13239 | + kaweth->status &= ~KAWETH_STATUS_SUSPENDING; | |
13240 | + spin_unlock_irqrestore(&kaweth->device_lock, flags); | |
13241 | + | |
13242 | + if (!kaweth->opened) | |
13243 | + return 0; | |
13244 | + kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); | |
13245 | + kaweth_resubmit_int_urb(kaweth, GFP_NOIO); | |
13246 | + | |
13247 | + return 0; | |
13248 | +} | |
13249 | + | |
13250 | +/**************************************************************** | |
13251 | + * kaweth_probe | |
13252 | + ****************************************************************/ | |
13253 | + | |
13254 | + | |
13255 | +static const struct net_device_ops kaweth_netdev_ops = { | |
13256 | + .ndo_open = kaweth_open, | |
13257 | + .ndo_stop = kaweth_close, | |
13258 | + .ndo_start_xmit = kaweth_start_xmit, | |
13259 | + .ndo_tx_timeout = kaweth_tx_timeout, | |
13260 | + .ndo_set_rx_mode = kaweth_set_rx_mode, | |
13261 | + .ndo_get_stats = kaweth_netdev_stats, | |
13262 | + .ndo_change_mtu = eth_change_mtu, | |
13263 | + .ndo_set_mac_address = eth_mac_addr, | |
13264 | + .ndo_validate_addr = eth_validate_addr, | |
13265 | +}; | |
13266 | + | |
13267 | +static int kaweth_probe( | |
13268 | + struct usb_interface *intf, | |
13269 | + const struct usb_device_id *id /* from id_table */ | |
13270 | + ) | |
13271 | +{ | |
13272 | + struct device *dev = &intf->dev; | |
13273 | + struct usb_device *udev = interface_to_usbdev(intf); | |
13274 | + struct kaweth_device *kaweth; | |
13275 | + struct net_device *netdev; | |
13276 | + const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | |
13277 | + int result = 0; | |
13278 | + | |
13279 | + dev_dbg(dev, | |
13280 | + "Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n", | |
13281 | + udev->devnum, le16_to_cpu(udev->descriptor.idVendor), | |
13282 | + le16_to_cpu(udev->descriptor.idProduct), | |
13283 | + le16_to_cpu(udev->descriptor.bcdDevice)); | |
13284 | + | |
13285 | + dev_dbg(dev, "Device at %p\n", udev); | |
13286 | + | |
13287 | + dev_dbg(dev, "Descriptor length: %x type: %x\n", | |
13288 | + (int)udev->descriptor.bLength, | |
13289 | + (int)udev->descriptor.bDescriptorType); | |
13290 | + | |
13291 | + netdev = alloc_etherdev(sizeof(*kaweth)); | |
13292 | + if (!netdev) | |
13293 | + return -ENOMEM; | |
13294 | + | |
13295 | + kaweth = netdev_priv(netdev); | |
13296 | + kaweth->dev = udev; | |
13297 | + kaweth->net = netdev; | |
13298 | + | |
13299 | + spin_lock_init(&kaweth->device_lock); | |
13300 | + init_waitqueue_head(&kaweth->term_wait); | |
13301 | + | |
13302 | + dev_dbg(dev, "Resetting.\n"); | |
13303 | + | |
13304 | + kaweth_reset(kaweth); | |
13305 | + | |
13306 | + /* | |
13307 | + * If high byte of bcdDevice is nonzero, firmware is already | |
13308 | + * downloaded. Don't try to do it again, or we'll hang the device. | |
13309 | + */ | |
13310 | + | |
13311 | + if (le16_to_cpu(udev->descriptor.bcdDevice) >> 8) { | |
13312 | + dev_info(dev, "Firmware present in device.\n"); | |
13313 | + } else { | |
13314 | + /* Download the firmware */ | |
13315 | + dev_info(dev, "Downloading firmware...\n"); | |
13316 | + kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); | |
13317 | + if ((result = kaweth_download_firmware(kaweth, | |
13318 | + "kaweth/new_code.bin", | |
13319 | + 100, | |
13320 | + 2)) < 0) { | |
13321 | + dev_err(dev, "Error downloading firmware (%d)\n", | |
13322 | + result); | |
13323 | + goto err_fw; | |
13324 | + } | |
13325 | + | |
13326 | + if ((result = kaweth_download_firmware(kaweth, | |
13327 | + "kaweth/new_code_fix.bin", | |
13328 | + 100, | |
13329 | + 3)) < 0) { | |
13330 | + dev_err(dev, "Error downloading firmware fix (%d)\n", | |
13331 | + result); | |
13332 | + goto err_fw; | |
13333 | + } | |
13334 | + | |
13335 | + if ((result = kaweth_download_firmware(kaweth, | |
13336 | + "kaweth/trigger_code.bin", | |
13337 | + 126, | |
13338 | + 2)) < 0) { | |
13339 | + dev_err(dev, "Error downloading trigger code (%d)\n", | |
13340 | + result); | |
13341 | + goto err_fw; | |
13342 | + | |
13343 | + } | |
13344 | + | |
13345 | + if ((result = kaweth_download_firmware(kaweth, | |
13346 | + "kaweth/trigger_code_fix.bin", | |
13347 | + 126, | |
13348 | + 3)) < 0) { | |
13349 | + dev_err(dev, "Error downloading trigger code fix (%d)\n", result); | |
13350 | + goto err_fw; | |
13351 | + } | |
13352 | + | |
13353 | + | |
13354 | + if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { | |
13355 | + dev_err(dev, "Error triggering firmware (%d)\n", result); | |
13356 | + goto err_fw; | |
13357 | + } | |
13358 | + | |
13359 | + /* Device will now disappear for a moment... */ | |
13360 | + dev_info(dev, "Firmware loaded. I'll be back...\n"); | |
13361 | +err_fw: | |
13362 | + free_page((unsigned long)kaweth->firmware_buf); | |
13363 | + free_netdev(netdev); | |
13364 | + return -EIO; | |
13365 | + } | |
13366 | + | |
13367 | + result = kaweth_read_configuration(kaweth); | |
13368 | + | |
13369 | + if(result < 0) { | |
13370 | + dev_err(dev, "Error reading configuration (%d), no net device created\n", result); | |
13371 | + goto err_free_netdev; | |
13372 | + } | |
13373 | + | |
13374 | + dev_info(dev, "Statistics collection: %x\n", kaweth->configuration.statistics_mask); | |
13375 | + dev_info(dev, "Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); | |
13376 | + dev_info(dev, "MTU: %d\n", le16_to_cpu(kaweth->configuration.segment_size)); | |
13377 | + dev_info(dev, "Read MAC address %pM\n", kaweth->configuration.hw_addr); | |
13378 | + | |
13379 | + if(!memcmp(&kaweth->configuration.hw_addr, | |
13380 | + &bcast_addr, | |
13381 | + sizeof(bcast_addr))) { | |
13382 | + dev_err(dev, "Firmware not functioning properly, no net device created\n"); | |
13383 | + goto err_free_netdev; | |
13384 | + } | |
13385 | + | |
13386 | + if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { | |
13387 | + dev_dbg(dev, "Error setting URB size\n"); | |
13388 | + goto err_free_netdev; | |
13389 | + } | |
13390 | + | |
13391 | + if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { | |
13392 | + dev_err(dev, "Error setting SOFS wait\n"); | |
13393 | + goto err_free_netdev; | |
13394 | + } | |
13395 | + | |
13396 | + result = kaweth_set_receive_filter(kaweth, | |
13397 | + KAWETH_PACKET_FILTER_DIRECTED | | |
13398 | + KAWETH_PACKET_FILTER_BROADCAST | | |
13399 | + KAWETH_PACKET_FILTER_MULTICAST); | |
13400 | + | |
13401 | + if(result < 0) { | |
13402 | + dev_err(dev, "Error setting receive filter\n"); | |
13403 | + goto err_free_netdev; | |
13404 | + } | |
13405 | + | |
13406 | + dev_dbg(dev, "Initializing net device.\n"); | |
13407 | + | |
13408 | + kaweth->intf = intf; | |
13409 | + | |
13410 | + kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
13411 | + if (!kaweth->tx_urb) | |
13412 | + goto err_free_netdev; | |
13413 | + kaweth->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
13414 | + if (!kaweth->rx_urb) | |
13415 | + goto err_only_tx; | |
13416 | + kaweth->irq_urb = usb_alloc_urb(0, GFP_KERNEL); | |
13417 | + if (!kaweth->irq_urb) | |
13418 | + goto err_tx_and_rx; | |
13419 | + | |
13420 | + kaweth->intbuffer = usb_alloc_coherent( kaweth->dev, | |
13421 | + INTBUFFERSIZE, | |
13422 | + GFP_KERNEL, | |
13423 | + &kaweth->intbufferhandle); | |
13424 | + if (!kaweth->intbuffer) | |
13425 | + goto err_tx_and_rx_and_irq; | |
13426 | + kaweth->rx_buf = usb_alloc_coherent( kaweth->dev, | |
13427 | + KAWETH_BUF_SIZE, | |
13428 | + GFP_KERNEL, | |
13429 | + &kaweth->rxbufferhandle); | |
13430 | + if (!kaweth->rx_buf) | |
13431 | + goto err_all_but_rxbuf; | |
13432 | + | |
13433 | + memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr)); | |
13434 | + memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr, | |
13435 | + sizeof(kaweth->configuration.hw_addr)); | |
13436 | + | |
13437 | + netdev->netdev_ops = &kaweth_netdev_ops; | |
13438 | + netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; | |
13439 | + netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); | |
13440 | + netdev->ethtool_ops = &ops; | |
13441 | + | |
13442 | + /* kaweth is zeroed as part of alloc_netdev */ | |
13443 | + INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); | |
13444 | + usb_set_intfdata(intf, kaweth); | |
13445 | + | |
13446 | +#if 0 | |
13447 | +// dma_supported() is deeply broken on almost all architectures | |
13448 | + if (dma_supported (dev, 0xffffffffffffffffULL)) | |
13449 | + kaweth->net->features |= NETIF_F_HIGHDMA; | |
13450 | +#endif | |
13451 | + | |
13452 | + SET_NETDEV_DEV(netdev, dev); | |
13453 | + if (register_netdev(netdev) != 0) { | |
13454 | + dev_err(dev, "Error registering netdev.\n"); | |
13455 | + goto err_intfdata; | |
13456 | + } | |
13457 | + | |
13458 | + dev_info(dev, "kaweth interface created at %s\n", | |
13459 | + kaweth->net->name); | |
13460 | + | |
13461 | + dev_dbg(dev, "Kaweth probe returning.\n"); | |
13462 | + | |
13463 | + return 0; | |
13464 | + | |
13465 | +err_intfdata: | |
13466 | + usb_set_intfdata(intf, NULL); | |
13467 | + usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); | |
13468 | +err_all_but_rxbuf: | |
13469 | + usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); | |
13470 | +err_tx_and_rx_and_irq: | |
13471 | + usb_free_urb(kaweth->irq_urb); | |
13472 | +err_tx_and_rx: | |
13473 | + usb_free_urb(kaweth->rx_urb); | |
13474 | +err_only_tx: | |
13475 | + usb_free_urb(kaweth->tx_urb); | |
13476 | +err_free_netdev: | |
13477 | + free_netdev(netdev); | |
13478 | + | |
13479 | + return -EIO; | |
13480 | +} | |
13481 | + | |
13482 | +/**************************************************************** | |
13483 | + * kaweth_disconnect | |
13484 | + ****************************************************************/ | |
13485 | +static void kaweth_disconnect(struct usb_interface *intf) | |
13486 | +{ | |
13487 | + struct kaweth_device *kaweth = usb_get_intfdata(intf); | |
13488 | + struct net_device *netdev; | |
13489 | + | |
13490 | + dev_info(&intf->dev, "Unregistering\n"); | |
13491 | + | |
13492 | + usb_set_intfdata(intf, NULL); | |
13493 | + if (!kaweth) { | |
13494 | + dev_warn(&intf->dev, "unregistering non-existent device\n"); | |
13495 | + return; | |
13496 | + } | |
13497 | + netdev = kaweth->net; | |
13498 | + | |
13499 | + netdev_dbg(kaweth->net, "Unregistering net device\n"); | |
13500 | + unregister_netdev(netdev); | |
13501 | + | |
13502 | + usb_free_urb(kaweth->rx_urb); | |
13503 | + usb_free_urb(kaweth->tx_urb); | |
13504 | + usb_free_urb(kaweth->irq_urb); | |
13505 | + | |
13506 | + usb_free_coherent(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); | |
13507 | + usb_free_coherent(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); | |
13508 | + | |
13509 | + free_netdev(netdev); | |
13510 | +} | |
13511 | + | |
13512 | + | |
13513 | +// FIXME this completion stuff is a modified clone of | |
13514 | +// an OLD version of some stuff in usb.c ... | |
13515 | +struct usb_api_data { | |
13516 | + wait_queue_head_t wqh; | |
13517 | + int done; | |
13518 | +}; | |
13519 | + | |
13520 | +/*-------------------------------------------------------------------* | |
13521 | + * completion handler for compatibility wrappers (sync control/bulk) * | |
13522 | + *-------------------------------------------------------------------*/ | |
13523 | +static void usb_api_blocking_completion(struct urb *urb) | |
13524 | +{ | |
13525 | + struct usb_api_data *awd = (struct usb_api_data *)urb->context; | |
13526 | + | |
13527 | + awd->done=1; | |
13528 | + wake_up(&awd->wqh); | |
13529 | +} | |
13530 | + | |
13531 | +/*-------------------------------------------------------------------* | |
13532 | + * COMPATIBILITY STUFF * | |
13533 | + *-------------------------------------------------------------------*/ | |
13534 | + | |
13535 | +// Starts urb and waits for completion or timeout | |
13536 | +static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) | |
13537 | +{ | |
13538 | + struct usb_api_data awd; | |
13539 | + int status; | |
13540 | + | |
13541 | + init_waitqueue_head(&awd.wqh); | |
13542 | + awd.done = 0; | |
13543 | + | |
13544 | + urb->context = &awd; | |
13545 | + status = usb_submit_urb(urb, GFP_NOIO); | |
13546 | + if (status) { | |
13547 | + // something went wrong | |
13548 | + usb_free_urb(urb); | |
13549 | + return status; | |
13550 | + } | |
13551 | + | |
13552 | + if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { | |
13553 | + // timeout | |
13554 | + dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n"); | |
13555 | + usb_kill_urb(urb); // remove urb safely | |
13556 | + status = -ETIMEDOUT; | |
13557 | + } | |
13558 | + else { | |
13559 | + status = urb->status; | |
13560 | + } | |
13561 | + | |
13562 | + if (actual_length) { | |
13563 | + *actual_length = urb->actual_length; | |
13564 | + } | |
13565 | + | |
13566 | + usb_free_urb(urb); | |
13567 | + return status; | |
13568 | +} | |
13569 | + | |
13570 | +/*-------------------------------------------------------------------*/ | |
13571 | +// returns status (negative) or length (positive) | |
13572 | +static int kaweth_internal_control_msg(struct usb_device *usb_dev, | |
13573 | + unsigned int pipe, | |
13574 | + struct usb_ctrlrequest *cmd, void *data, | |
13575 | + int len, int timeout) | |
13576 | +{ | |
13577 | + struct urb *urb; | |
13578 | + int retv; | |
13579 | + int length = 0; /* shut up GCC */ | |
13580 | + | |
13581 | + urb = usb_alloc_urb(0, GFP_ATOMIC); | |
13582 | + if (!urb) | |
13583 | + return -ENOMEM; | |
13584 | + | |
13585 | + usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, | |
13586 | + len, usb_api_blocking_completion, NULL); | |
13587 | + | |
13588 | + retv = usb_start_wait_urb(urb, timeout, &length); | |
13589 | + if (retv < 0) { | |
13590 | + return retv; | |
13591 | + } | |
13592 | + else { | |
13593 | + return length; | |
13594 | + } | |
13595 | +} | |
13596 | + | |
13597 | +module_usb_driver(kaweth_driver); | |
13598 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/Kconfig backports-3.18.1-1/drivers/net/usb/Kconfig | |
13599 | --- backports-3.18.1-1.org/drivers/net/usb/Kconfig 2014-12-21 22:37:15.000000000 +0100 | |
13600 | +++ backports-3.18.1-1/drivers/net/usb/Kconfig 2015-01-03 15:19:02.310281530 +0100 | |
13601 | @@ -13,7 +13,6 @@ | |
13602 | if USB_NET_DRIVERS | |
13603 | ||
13604 | config USB_CATC | |
13605 | - depends on n | |
13606 | tristate "USB CATC NetMate-based Ethernet device support" | |
13607 | depends on m | |
13608 | depends on CRC32 | |
13609 | @@ -34,7 +33,6 @@ | |
13610 | module will be called catc. | |
13611 | ||
13612 | config USB_KAWETH | |
13613 | - depends on n | |
13614 | tristate "USB KLSI KL5USB101-based ethernet device support" | |
13615 | depends on m | |
13616 | ---help--- | |
13617 | @@ -75,7 +73,6 @@ | |
13618 | module will be called kaweth. | |
13619 | ||
13620 | config USB_PEGASUS | |
13621 | - depends on n | |
13622 | tristate "USB Pegasus/Pegasus-II based ethernet device support" | |
13623 | depends on m | |
13624 | select BACKPORT_MII | |
13625 | @@ -92,7 +89,6 @@ | |
13626 | module will be called pegasus. | |
13627 | ||
13628 | config USB_RTL8150 | |
13629 | - depends on n | |
13630 | tristate "USB RTL8150 based ethernet device support" | |
13631 | depends on m | |
13632 | select BACKPORT_MII | |
13633 | @@ -105,7 +101,6 @@ | |
13634 | module will be called rtl8150. | |
13635 | ||
13636 | config USB_RTL8152 | |
13637 | - depends on n | |
13638 | tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" | |
13639 | depends on m | |
13640 | select BACKPORT_MII | |
13641 | @@ -153,7 +148,6 @@ | |
13642 | module will be called usbnet. | |
13643 | ||
13644 | config USB_NET_AX8817X | |
13645 | - depends on n | |
13646 | tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" | |
13647 | depends on m | |
13648 | depends on USB_USBNET | |
13649 | @@ -183,7 +177,6 @@ | |
13650 | what other networking devices you have in use. | |
13651 | ||
13652 | config USB_NET_AX88179_178A | |
13653 | - depends on n | |
13654 | tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet" | |
13655 | depends on m | |
13656 | depends on USB_USBNET | |
13657 | @@ -232,7 +225,6 @@ | |
13658 | name is used instead. | |
13659 | ||
13660 | config USB_NET_CDC_EEM | |
13661 | - depends on n | |
13662 | tristate "CDC EEM support" | |
13663 | depends on m | |
13664 | depends on USB_USBNET | |
13665 | @@ -268,7 +260,6 @@ | |
13666 | * Ericsson F5521gw Mobile Broadband Module | |
13667 | ||
13668 | config USB_NET_HUAWEI_CDC_NCM | |
13669 | - depends on n | |
13670 | tristate "Huawei NCM embedded AT channel support" | |
13671 | depends on m | |
13672 | depends on USB_USBNET | |
13673 | @@ -304,7 +295,6 @@ | |
13674 | module will be called cdc_mbim. | |
13675 | ||
13676 | config USB_NET_DM9601 | |
13677 | - depends on n | |
13678 | tristate "Davicom DM96xx based USB 10/100 ethernet devices" | |
13679 | depends on m | |
13680 | depends on USB_USBNET | |
13681 | @@ -314,7 +304,6 @@ | |
13682 | based USB 10/100 Ethernet adapters. | |
13683 | ||
13684 | config USB_NET_SR9700 | |
13685 | - depends on n | |
13686 | tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices" | |
13687 | depends on m | |
13688 | depends on USB_USBNET | |
13689 | @@ -324,7 +313,6 @@ | |
13690 | 10/100 Ethernet adapters. | |
13691 | ||
13692 | config USB_NET_SR9800 | |
13693 | - depends on n | |
13694 | tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices" | |
13695 | depends on m | |
13696 | depends on USB_USBNET | |
13697 | @@ -341,7 +329,6 @@ | |
13698 | module will be called sr9800. | |
13699 | ||
13700 | config USB_NET_SMSC75XX | |
13701 | - depends on n | |
13702 | tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" | |
13703 | depends on m | |
13704 | depends on USB_USBNET | |
13705 | @@ -353,7 +340,6 @@ | |
13706 | Gigabit Ethernet adapters. | |
13707 | ||
13708 | config USB_NET_SMSC95XX | |
13709 | - depends on n | |
13710 | tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices" | |
13711 | depends on m | |
13712 | depends on USB_USBNET | |
13713 | @@ -365,7 +351,6 @@ | |
13714 | 10/100 Ethernet adapters. | |
13715 | ||
13716 | config USB_NET_GL620A | |
13717 | - depends on n | |
13718 | tristate "GeneSys GL620USB-A based cables" | |
13719 | depends on m | |
13720 | depends on USB_USBNET | |
13721 | @@ -376,7 +361,6 @@ | |
13722 | Note that the half-duplex "GL620USB" is not supported. | |
13723 | ||
13724 | config USB_NET_NET1080 | |
13725 | - depends on n | |
13726 | tristate "NetChip 1080 based cables (Laplink, ...)" | |
13727 | depends on m | |
13728 | default y | |
13729 | @@ -387,7 +371,6 @@ | |
13730 | optionally with LEDs that indicate traffic | |
13731 | ||
13732 | config USB_NET_PLUSB | |
13733 | - depends on n | |
13734 | tristate "Prolific PL-2301/2302/25A1 based cables" | |
13735 | depends on m | |
13736 | # if the handshake/init/reset problems, from original 'plusb', | |
13737 | @@ -398,7 +381,6 @@ | |
13738 | with one of these chips. | |
13739 | ||
13740 | config USB_NET_MCS7830 | |
13741 | - depends on n | |
13742 | tristate "MosChip MCS7830 based Ethernet adapters" | |
13743 | depends on m | |
13744 | depends on USB_USBNET | |
13745 | @@ -424,7 +406,6 @@ | |
13746 | (and for) Microsoft; it isn't an "Open" ecosystem or market. | |
13747 | ||
13748 | config USB_NET_CDC_SUBSET | |
13749 | - depends on n | |
13750 | tristate "Simple USB Network Links (CDC Ethernet subset)" | |
13751 | depends on m | |
13752 | depends on USB_USBNET | |
13753 | @@ -496,7 +477,6 @@ | |
13754 | with one of these chips. | |
13755 | ||
13756 | config USB_NET_ZAURUS | |
13757 | - depends on n | |
13758 | tristate "Sharp Zaurus (stock ROMs) and compatible" | |
13759 | depends on m | |
13760 | depends on USB_USBNET | |
13761 | @@ -516,7 +496,6 @@ | |
13762 | some cases CDC MDLM) protocol, not "g_ether". | |
13763 | ||
13764 | config USB_NET_CX82310_ETH | |
13765 | - depends on n | |
13766 | tristate "Conexant CX82310 USB ethernet port" | |
13767 | depends on m | |
13768 | depends on USB_USBNET | |
13769 | @@ -526,7 +505,6 @@ | |
13770 | it will not work with ADSL modems (use cxacru driver instead). | |
13771 | ||
13772 | config USB_NET_KALMIA | |
13773 | - depends on n | |
13774 | tristate "Samsung Kalmia based LTE USB modem" | |
13775 | depends on m | |
13776 | depends on USB_USBNET | |
13777 | @@ -561,7 +539,6 @@ | |
13778 | module will be called qmi_wwan. | |
13779 | ||
13780 | config USB_HSO | |
13781 | - depends on n | |
13782 | tristate "Option USB High Speed Mobile Devices" | |
13783 | depends on m | |
13784 | depends on USB && RFKILL && TTY | |
13785 | @@ -574,7 +551,6 @@ | |
13786 | module will be called hso. | |
13787 | ||
13788 | config USB_NET_INT51X1 | |
13789 | - depends on n | |
13790 | tristate "Intellon PLC based usb adapter" | |
13791 | depends on m | |
13792 | depends on USB_USBNET | |
13793 | @@ -584,7 +560,6 @@ | |
13794 | INT51x1/INT5200 chip, like the "devolo dLan duo". | |
13795 | ||
13796 | config USB_CDC_PHONET | |
13797 | - depends on n | |
13798 | tristate "CDC Phonet support" | |
13799 | depends on m | |
13800 | depends on PHONET | |
13801 | @@ -594,7 +569,6 @@ | |
13802 | "PC suite" USB profile. | |
13803 | ||
13804 | config USB_IPHETH | |
13805 | - depends on n | |
13806 | tristate "Apple iPhone USB Ethernet driver" | |
13807 | depends on m | |
13808 | default n | |
13809 | @@ -618,11 +592,10 @@ | |
13810 | module will be called sierra_net. | |
13811 | ||
13812 | config USB_VL600 | |
13813 | - depends on n | |
13814 | tristate "LG VL600 modem dongle" | |
13815 | depends on m | |
13816 | depends on USB_NET_CDCETHER && TTY | |
13817 | - select USB_ACM | |
13818 | +# depends on USB_ACM | |
13819 | help | |
13820 | Select this if you want to use an LG Electronics 4G/LTE usb modem | |
13821 | called VL600. This driver only handles the ethernet | |
13822 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/lg-vl600.c backports-3.18.1-1/drivers/net/usb/lg-vl600.c | |
13823 | --- backports-3.18.1-1.org/drivers/net/usb/lg-vl600.c 1970-01-01 01:00:00.000000000 +0100 | |
13824 | +++ backports-3.18.1-1/drivers/net/usb/lg-vl600.c 2014-12-16 18:39:45.000000000 +0100 | |
13825 | @@ -0,0 +1,353 @@ | |
13826 | +/* | |
13827 | + * Ethernet interface part of the LG VL600 LTE modem (4G dongle) | |
13828 | + * | |
13829 | + * Copyright (C) 2011 Intel Corporation | |
13830 | + * Author: Andrzej Zaborowski <balrogg@gmail.com> | |
13831 | + * | |
13832 | + * This program is free software; you can redistribute it and/or modify | |
13833 | + * it under the terms of the GNU General Public License as published by | |
13834 | + * the Free Software Foundation; either version 2 of the License, or | |
13835 | + * (at your option) any later version. | |
13836 | + * | |
13837 | + * This program is distributed in the hope that it will be useful, | |
13838 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13839 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13840 | + * GNU General Public License for more details. | |
13841 | + * | |
13842 | + * You should have received a copy of the GNU General Public License | |
13843 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
13844 | + */ | |
13845 | +#include <linux/etherdevice.h> | |
13846 | +#include <linux/ethtool.h> | |
13847 | +#include <linux/mii.h> | |
13848 | +#include <linux/usb.h> | |
13849 | +#include <linux/usb/cdc.h> | |
13850 | +#include <linux/usb/usbnet.h> | |
13851 | +#include <linux/if_ether.h> | |
13852 | +#include <linux/if_arp.h> | |
13853 | +#include <linux/inetdevice.h> | |
13854 | +#include <linux/module.h> | |
13855 | + | |
13856 | +/* | |
13857 | + * The device has a CDC ACM port for modem control (it claims to be | |
13858 | + * CDC ACM anyway) and a CDC Ethernet port for actual network data. | |
13859 | + * It will however ignore data on both ports that is not encapsulated | |
13860 | + * in a specific way, any data returned is also encapsulated the same | |
13861 | + * way. The headers don't seem to follow any popular standard. | |
13862 | + * | |
13863 | + * This driver adds and strips these headers from the ethernet frames | |
13864 | + * sent/received from the CDC Ethernet port. The proprietary header | |
13865 | + * replaces the standard ethernet header in a packet so only actual | |
13866 | + * ethernet frames are allowed. The headers allow some form of | |
13867 | + * multiplexing by using non standard values of the .h_proto field. | |
13868 | + * Windows/Mac drivers do send a couple of such frames to the device | |
13869 | + * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what | |
13870 | + * seems to be) a flag in the .dummy_flags. This doesn't seem necessary | |
13871 | + * for modem operation but can possibly be used for GPS or other funcitons. | |
13872 | + */ | |
13873 | + | |
13874 | +struct vl600_frame_hdr { | |
13875 | + __le32 len; | |
13876 | + __le32 serial; | |
13877 | + __le32 pkt_cnt; | |
13878 | + __le32 dummy_flags; | |
13879 | + __le32 dummy; | |
13880 | + __le32 magic; | |
13881 | +} __attribute__((packed)); | |
13882 | + | |
13883 | +struct vl600_pkt_hdr { | |
13884 | + __le32 dummy[2]; | |
13885 | + __le32 len; | |
13886 | + __be16 h_proto; | |
13887 | +} __attribute__((packed)); | |
13888 | + | |
13889 | +struct vl600_state { | |
13890 | + struct sk_buff *current_rx_buf; | |
13891 | +}; | |
13892 | + | |
13893 | +static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) | |
13894 | +{ | |
13895 | + int ret; | |
13896 | + struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL); | |
13897 | + | |
13898 | + if (!s) | |
13899 | + return -ENOMEM; | |
13900 | + | |
13901 | + ret = usbnet_cdc_bind(dev, intf); | |
13902 | + if (ret) { | |
13903 | + kfree(s); | |
13904 | + return ret; | |
13905 | + } | |
13906 | + | |
13907 | + dev->driver_priv = s; | |
13908 | + | |
13909 | + /* ARP packets don't go through, but they're also of no use. The | |
13910 | + * subnet has only two hosts anyway: us and the gateway / DHCP | |
13911 | + * server (probably simulated by modem firmware or network operator) | |
13912 | + * whose address changes everytime we connect to the intarwebz and | |
13913 | + * who doesn't bother answering ARP requests either. So hardware | |
13914 | + * addresses have no meaning, the destination and the source of every | |
13915 | + * packet depend only on whether it is on the IN or OUT endpoint. */ | |
13916 | + dev->net->flags |= IFF_NOARP; | |
13917 | + /* IPv6 NDP relies on multicast. Enable it by default. */ | |
13918 | + dev->net->flags |= IFF_MULTICAST; | |
13919 | + | |
13920 | + return ret; | |
13921 | +} | |
13922 | + | |
13923 | +static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf) | |
13924 | +{ | |
13925 | + struct vl600_state *s = dev->driver_priv; | |
13926 | + | |
13927 | + if (s->current_rx_buf) | |
13928 | + dev_kfree_skb(s->current_rx_buf); | |
13929 | + | |
13930 | + kfree(s); | |
13931 | + | |
13932 | + return usbnet_cdc_unbind(dev, intf); | |
13933 | +} | |
13934 | + | |
13935 | +static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
13936 | +{ | |
13937 | + struct vl600_frame_hdr *frame; | |
13938 | + struct vl600_pkt_hdr *packet; | |
13939 | + struct ethhdr *ethhdr; | |
13940 | + int packet_len, count; | |
13941 | + struct sk_buff *buf = skb; | |
13942 | + struct sk_buff *clone; | |
13943 | + struct vl600_state *s = dev->driver_priv; | |
13944 | + | |
13945 | + /* Frame lengths are generally 4B multiplies but every couple of | |
13946 | + * hours there's an odd number of bytes sized yet correct frame, | |
13947 | + * so don't require this. */ | |
13948 | + | |
13949 | + /* Allow a packet (or multiple packets batched together) to be | |
13950 | + * split across many frames. We don't allow a new batch to | |
13951 | + * begin in the same frame another one is ending however, and no | |
13952 | + * leading or trailing pad bytes. */ | |
13953 | + if (s->current_rx_buf) { | |
13954 | + frame = (struct vl600_frame_hdr *) s->current_rx_buf->data; | |
13955 | + if (skb->len + s->current_rx_buf->len > | |
13956 | + le32_to_cpup(&frame->len)) { | |
13957 | + netif_err(dev, ifup, dev->net, "Fragment too long\n"); | |
13958 | + dev->net->stats.rx_length_errors++; | |
13959 | + goto error; | |
13960 | + } | |
13961 | + | |
13962 | + buf = s->current_rx_buf; | |
13963 | + memcpy(skb_put(buf, skb->len), skb->data, skb->len); | |
13964 | + } else if (skb->len < 4) { | |
13965 | + netif_err(dev, ifup, dev->net, "Frame too short\n"); | |
13966 | + dev->net->stats.rx_length_errors++; | |
13967 | + goto error; | |
13968 | + } | |
13969 | + | |
13970 | + frame = (struct vl600_frame_hdr *) buf->data; | |
13971 | + /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48), | |
13972 | + * otherwise we may run out of memory w/a bad packet */ | |
13973 | + if (ntohl(frame->magic) != 0x53544448 && | |
13974 | + ntohl(frame->magic) != 0x44544d48) | |
13975 | + goto error; | |
13976 | + | |
13977 | + if (buf->len < sizeof(*frame) || | |
13978 | + buf->len != le32_to_cpup(&frame->len)) { | |
13979 | + /* Save this fragment for later assembly */ | |
13980 | + if (s->current_rx_buf) | |
13981 | + return 0; | |
13982 | + | |
13983 | + s->current_rx_buf = skb_copy_expand(skb, 0, | |
13984 | + le32_to_cpup(&frame->len), GFP_ATOMIC); | |
13985 | + if (!s->current_rx_buf) { | |
13986 | + netif_err(dev, ifup, dev->net, "Reserving %i bytes " | |
13987 | + "for packet assembly failed.\n", | |
13988 | + le32_to_cpup(&frame->len)); | |
13989 | + dev->net->stats.rx_errors++; | |
13990 | + } | |
13991 | + | |
13992 | + return 0; | |
13993 | + } | |
13994 | + | |
13995 | + count = le32_to_cpup(&frame->pkt_cnt); | |
13996 | + | |
13997 | + skb_pull(buf, sizeof(*frame)); | |
13998 | + | |
13999 | + while (count--) { | |
14000 | + if (buf->len < sizeof(*packet)) { | |
14001 | + netif_err(dev, ifup, dev->net, "Packet too short\n"); | |
14002 | + goto error; | |
14003 | + } | |
14004 | + | |
14005 | + packet = (struct vl600_pkt_hdr *) buf->data; | |
14006 | + packet_len = sizeof(*packet) + le32_to_cpup(&packet->len); | |
14007 | + if (packet_len > buf->len) { | |
14008 | + netif_err(dev, ifup, dev->net, | |
14009 | + "Bad packet length stored in header\n"); | |
14010 | + goto error; | |
14011 | + } | |
14012 | + | |
14013 | + /* Packet header is same size as the ethernet header | |
14014 | + * (sizeof(*packet) == sizeof(*ethhdr)), additionally | |
14015 | + * the h_proto field is in the same place so we just leave it | |
14016 | + * alone and fill in the remaining fields. | |
14017 | + */ | |
14018 | + ethhdr = (struct ethhdr *) skb->data; | |
14019 | + if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP && | |
14020 | + buf->len > 0x26) { | |
14021 | + /* Copy the addresses from packet contents */ | |
14022 | + memcpy(ethhdr->h_source, | |
14023 | + &buf->data[sizeof(*ethhdr) + 0x8], | |
14024 | + ETH_ALEN); | |
14025 | + memcpy(ethhdr->h_dest, | |
14026 | + &buf->data[sizeof(*ethhdr) + 0x12], | |
14027 | + ETH_ALEN); | |
14028 | + } else { | |
14029 | + memset(ethhdr->h_source, 0, ETH_ALEN); | |
14030 | + memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); | |
14031 | + | |
14032 | + /* Inbound IPv6 packets have an IPv4 ethertype (0x800) | |
14033 | + * for some reason. Peek at the L3 header to check | |
14034 | + * for IPv6 packets, and set the ethertype to IPv6 | |
14035 | + * (0x86dd) so Linux can understand it. | |
14036 | + */ | |
14037 | + if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60) | |
14038 | + ethhdr->h_proto = htons(ETH_P_IPV6); | |
14039 | + } | |
14040 | + | |
14041 | + if (count) { | |
14042 | + /* Not the last packet in this batch */ | |
14043 | + clone = skb_clone(buf, GFP_ATOMIC); | |
14044 | + if (!clone) | |
14045 | + goto error; | |
14046 | + | |
14047 | + skb_trim(clone, packet_len); | |
14048 | + usbnet_skb_return(dev, clone); | |
14049 | + | |
14050 | + skb_pull(buf, (packet_len + 3) & ~3); | |
14051 | + } else { | |
14052 | + skb_trim(buf, packet_len); | |
14053 | + | |
14054 | + if (s->current_rx_buf) { | |
14055 | + usbnet_skb_return(dev, buf); | |
14056 | + s->current_rx_buf = NULL; | |
14057 | + return 0; | |
14058 | + } | |
14059 | + | |
14060 | + return 1; | |
14061 | + } | |
14062 | + } | |
14063 | + | |
14064 | +error: | |
14065 | + if (s->current_rx_buf) { | |
14066 | + dev_kfree_skb_any(s->current_rx_buf); | |
14067 | + s->current_rx_buf = NULL; | |
14068 | + } | |
14069 | + dev->net->stats.rx_errors++; | |
14070 | + return 0; | |
14071 | +} | |
14072 | + | |
14073 | +static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, | |
14074 | + struct sk_buff *skb, gfp_t flags) | |
14075 | +{ | |
14076 | + struct sk_buff *ret; | |
14077 | + struct vl600_frame_hdr *frame; | |
14078 | + struct vl600_pkt_hdr *packet; | |
14079 | + static uint32_t serial = 1; | |
14080 | + int orig_len = skb->len - sizeof(struct ethhdr); | |
14081 | + int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3; | |
14082 | + | |
14083 | + frame = (struct vl600_frame_hdr *) skb->data; | |
14084 | + if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len)) | |
14085 | + return skb; /* Already encapsulated? */ | |
14086 | + | |
14087 | + if (skb->len < sizeof(struct ethhdr)) | |
14088 | + /* Drop, device can only deal with ethernet packets */ | |
14089 | + return NULL; | |
14090 | + | |
14091 | + if (!skb_cloned(skb)) { | |
14092 | + int headroom = skb_headroom(skb); | |
14093 | + int tailroom = skb_tailroom(skb); | |
14094 | + | |
14095 | + if (tailroom >= full_len - skb->len - sizeof(*frame) && | |
14096 | + headroom >= sizeof(*frame)) | |
14097 | + /* There's enough head and tail room */ | |
14098 | + goto encapsulate; | |
14099 | + | |
14100 | + if (headroom + tailroom + skb->len >= full_len) { | |
14101 | + /* There's enough total room, just readjust */ | |
14102 | + skb->data = memmove(skb->head + sizeof(*frame), | |
14103 | + skb->data, skb->len); | |
14104 | + skb_set_tail_pointer(skb, skb->len); | |
14105 | + goto encapsulate; | |
14106 | + } | |
14107 | + } | |
14108 | + | |
14109 | + /* Alloc a new skb with the required size */ | |
14110 | + ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len - | |
14111 | + skb->len - sizeof(struct vl600_frame_hdr), flags); | |
14112 | + dev_kfree_skb_any(skb); | |
14113 | + if (!ret) | |
14114 | + return ret; | |
14115 | + skb = ret; | |
14116 | + | |
14117 | +encapsulate: | |
14118 | + /* Packet header is same size as ethernet packet header | |
14119 | + * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the | |
14120 | + * h_proto field is in the same place so we just leave it alone and | |
14121 | + * overwrite the remaining fields. | |
14122 | + */ | |
14123 | + packet = (struct vl600_pkt_hdr *) skb->data; | |
14124 | + /* The VL600 wants IPv6 packets to have an IPv4 ethertype | |
14125 | + * Since this modem only supports IPv4 and IPv6, just set all | |
14126 | + * frames to 0x0800 (ETH_P_IP) | |
14127 | + */ | |
14128 | + packet->h_proto = htons(ETH_P_IP); | |
14129 | + memset(&packet->dummy, 0, sizeof(packet->dummy)); | |
14130 | + packet->len = cpu_to_le32(orig_len); | |
14131 | + | |
14132 | + frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); | |
14133 | + memset(frame, 0, sizeof(*frame)); | |
14134 | + frame->len = cpu_to_le32(full_len); | |
14135 | + frame->serial = cpu_to_le32(serial++); | |
14136 | + frame->pkt_cnt = cpu_to_le32(1); | |
14137 | + | |
14138 | + if (skb->len < full_len) /* Pad */ | |
14139 | + skb_put(skb, full_len - skb->len); | |
14140 | + | |
14141 | + return skb; | |
14142 | +} | |
14143 | + | |
14144 | +static const struct driver_info vl600_info = { | |
14145 | + .description = "LG VL600 modem", | |
14146 | + .flags = FLAG_RX_ASSEMBLE | FLAG_WWAN, | |
14147 | + .bind = vl600_bind, | |
14148 | + .unbind = vl600_unbind, | |
14149 | + .status = usbnet_cdc_status, | |
14150 | + .rx_fixup = vl600_rx_fixup, | |
14151 | + .tx_fixup = vl600_tx_fixup, | |
14152 | +}; | |
14153 | + | |
14154 | +static const struct usb_device_id products[] = { | |
14155 | + { | |
14156 | + USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, | |
14157 | + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | |
14158 | + .driver_info = (unsigned long) &vl600_info, | |
14159 | + }, | |
14160 | + {}, /* End */ | |
14161 | +}; | |
14162 | +MODULE_DEVICE_TABLE(usb, products); | |
14163 | + | |
14164 | +static struct usb_driver lg_vl600_driver = { | |
14165 | + .name = "lg-vl600", | |
14166 | + .id_table = products, | |
14167 | + .probe = usbnet_probe, | |
14168 | + .disconnect = usbnet_disconnect, | |
14169 | + .suspend = usbnet_suspend, | |
14170 | + .resume = usbnet_resume, | |
14171 | + .disable_hub_initiated_lpm = 1, | |
14172 | +}; | |
14173 | + | |
14174 | +module_usb_driver(lg_vl600_driver); | |
14175 | + | |
14176 | +MODULE_AUTHOR("Anrzej Zaborowski"); | |
14177 | +MODULE_DESCRIPTION("LG-VL600 modem's ethernet link"); | |
14178 | +MODULE_LICENSE("GPL"); | |
14179 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/Makefile backports-3.18.1-1/drivers/net/usb/Makefile | |
14180 | --- backports-3.18.1-1.org/drivers/net/usb/Makefile 2014-12-21 22:37:15.000000000 +0100 | |
14181 | +++ backports-3.18.1-1/drivers/net/usb/Makefile 2015-01-03 13:49:51.269970813 +0100 | |
14182 | @@ -1,39 +1,35 @@ | |
14183 | -# | |
14184 | -# Makefile for USB Network drivers | |
14185 | -# | |
14186 | -# | |
14187 | -#obj-$(CPTCFG_USB_CATC) += catc.o | |
14188 | -#obj-$(CPTCFG_USB_KAWETH) += kaweth.o | |
14189 | -#obj-$(CPTCFG_USB_PEGASUS) += pegasus.o | |
14190 | -#obj-$(CPTCFG_USB_RTL8150) += rtl8150.o | |
14191 | -#obj-$(CPTCFG_USB_RTL8152) += r8152.o | |
14192 | -#obj-$(CPTCFG_USB_HSO) += hso.o | |
14193 | -#obj-$(CPTCFG_USB_NET_AX8817X) += asix.o | |
14194 | -#obj-$(CPTCFG_USB_NET_AX88179_178A) += ax88179_178a.o | |
14195 | +obj-$(CPTCFG_USB_CATC) += catc.o | |
14196 | +obj-$(CPTCFG_USB_KAWETH) += kaweth.o | |
14197 | +obj-$(CPTCFG_USB_PEGASUS) += pegasus.o | |
14198 | +obj-$(CPTCFG_USB_RTL8150) += rtl8150.o | |
14199 | +obj-$(CPTCFG_USB_RTL8152) += r8152.o | |
14200 | +obj-$(CPTCFG_USB_HSO) += hso.o | |
14201 | +obj-$(CPTCFG_USB_NET_AX8817X) += asix.o | |
14202 | +asix-y := asix_devices.o asix_common.o ax88172a.o | |
14203 | +obj-$(CPTCFG_USB_NET_AX88179_178A) += ax88179_178a.o | |
14204 | obj-$(CPTCFG_USB_NET_CDCETHER) += cdc_ether.o | |
14205 | -#obj-$(CPTCFG_USB_NET_CDC_EEM) += cdc_eem.o | |
14206 | -#obj-$(CPTCFG_USB_NET_DM9601) += dm9601.o | |
14207 | -#obj-$(CPTCFG_USB_NET_SR9700) += sr9700.o | |
14208 | -#obj-$(CPTCFG_USB_NET_SR9800) += sr9800.o | |
14209 | -#obj-$(CPTCFG_USB_NET_SMSC75XX) += smsc75xx.o | |
14210 | -#obj-$(CPTCFG_USB_NET_SMSC95XX) += smsc95xx.o | |
14211 | -#obj-$(CPTCFG_USB_NET_GL620A) += gl620a.o | |
14212 | -#obj-$(CPTCFG_USB_NET_NET1080) += net1080.o | |
14213 | -#obj-$(CPTCFG_USB_NET_PLUSB) += plusb.o | |
14214 | +obj-$(CPTCFG_USB_NET_CDC_EEM) += cdc_eem.o | |
14215 | +obj-$(CPTCFG_USB_NET_DM9601) += dm9601.o | |
14216 | +obj-$(CPTCFG_USB_NET_SR9700) += sr9700.o | |
14217 | +obj-$(CPTCFG_USB_NET_SR9800) += sr9800.o | |
14218 | +obj-$(CPTCFG_USB_NET_SMSC75XX) += smsc75xx.o | |
14219 | +obj-$(CPTCFG_USB_NET_SMSC95XX) += smsc95xx.o | |
14220 | +obj-$(CPTCFG_USB_NET_GL620A) += gl620a.o | |
14221 | +obj-$(CPTCFG_USB_NET_NET1080) += net1080.o | |
14222 | +obj-$(CPTCFG_USB_NET_PLUSB) += plusb.o | |
14223 | obj-$(CPTCFG_USB_NET_RNDIS_HOST) += rndis_host.o | |
14224 | -#obj-$(CPTCFG_USB_NET_CDC_SUBSET) += cdc_subset.o | |
14225 | -#obj-$(CPTCFG_USB_NET_ZAURUS) += zaurus.o | |
14226 | -#obj-$(CPTCFG_USB_NET_MCS7830) += mcs7830.o | |
14227 | +obj-$(CPTCFG_USB_NET_CDC_SUBSET) += cdc_subset.o | |
14228 | +obj-$(CPTCFG_USB_NET_ZAURUS) += zaurus.o | |
14229 | +obj-$(CPTCFG_USB_NET_MCS7830) += mcs7830.o | |
14230 | obj-$(CPTCFG_USB_USBNET) += usbnet.o | |
14231 | -#obj-$(CPTCFG_USB_NET_INT51X1) += int51x1.o | |
14232 | -#obj-$(CPTCFG_USB_CDC_PHONET) += cdc-phonet.o | |
14233 | -#obj-$(CPTCFG_USB_NET_KALMIA) += kalmia.o | |
14234 | -#obj-$(CPTCFG_USB_IPHETH) += ipheth.o | |
14235 | +obj-$(CPTCFG_USB_NET_INT51X1) += int51x1.o | |
14236 | +obj-$(CPTCFG_USB_CDC_PHONET) += cdc-phonet.o | |
14237 | +obj-$(CPTCFG_USB_NET_KALMIA) += kalmia.o | |
14238 | +obj-$(CPTCFG_USB_IPHETH) += ipheth.o | |
14239 | obj-$(CPTCFG_USB_SIERRA_NET) += sierra_net.o | |
14240 | -#obj-$(CPTCFG_USB_NET_CX82310_ETH) += cx82310_eth.o | |
14241 | +obj-$(CPTCFG_USB_NET_CX82310_ETH) += cx82310_eth.o | |
14242 | obj-$(CPTCFG_USB_NET_CDC_NCM) += cdc_ncm.o | |
14243 | -#obj-$(CPTCFG_USB_NET_HUAWEI_CDC_NCM) += huawei_cdc_ncm.o | |
14244 | -#obj-$(CPTCFG_USB_VL600) += lg-vl600.o | |
14245 | +obj-$(CPTCFG_USB_NET_HUAWEI_CDC_NCM) += huawei_cdc_ncm.o | |
14246 | +obj-$(CPTCFG_USB_VL600) += lg-vl600.o | |
14247 | obj-$(CPTCFG_USB_NET_QMI_WWAN) += qmi_wwan.o | |
14248 | obj-$(CPTCFG_USB_NET_CDC_MBIM) += cdc_mbim.o | |
14249 | - | |
14250 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/mcs7830.c backports-3.18.1-1/drivers/net/usb/mcs7830.c | |
14251 | --- backports-3.18.1-1.org/drivers/net/usb/mcs7830.c 1970-01-01 01:00:00.000000000 +0100 | |
14252 | +++ backports-3.18.1-1/drivers/net/usb/mcs7830.c 2014-12-16 18:39:45.000000000 +0100 | |
14253 | @@ -0,0 +1,643 @@ | |
14254 | +/* | |
14255 | + * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices | |
14256 | + * | |
14257 | + * based on usbnet.c, asix.c and the vendor provided mcs7830 driver | |
14258 | + * | |
14259 | + * Copyright (C) 2010 Andreas Mohr <andi@lisas.de> | |
14260 | + * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> | |
14261 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> | |
14262 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> | |
14263 | + * Copyright (c) 2002-2003 TiVo Inc. | |
14264 | + * | |
14265 | + * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). | |
14266 | + * | |
14267 | + * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"), | |
14268 | + * per active notification by manufacturer | |
14269 | + * | |
14270 | + * TODO: | |
14271 | + * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) | |
14272 | + * - implement ethtool_ops get_pauseparam/set_pauseparam | |
14273 | + * via HIF_REG_PAUSE_THRESHOLD (>= revision C only!) | |
14274 | + * - implement get_eeprom/[set_eeprom] | |
14275 | + * - switch PHY on/off on ifup/ifdown (perhaps in usbnet.c, via MII) | |
14276 | + * - mcs7830_get_regs() handling is weird: for rev 2 we return 32 regs, | |
14277 | + * can access only ~ 24, remaining user buffer is uninitialized garbage | |
14278 | + * - anything else? | |
14279 | + * | |
14280 | + * | |
14281 | + * This program is free software; you can redistribute it and/or modify | |
14282 | + * it under the terms of the GNU General Public License as published by | |
14283 | + * the Free Software Foundation; either version 2 of the License, or | |
14284 | + * (at your option) any later version. | |
14285 | + * | |
14286 | + * This program is distributed in the hope that it will be useful, | |
14287 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14288 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14289 | + * GNU General Public License for more details. | |
14290 | + * | |
14291 | + * You should have received a copy of the GNU General Public License | |
14292 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
14293 | + */ | |
14294 | + | |
14295 | +#include <linux/crc32.h> | |
14296 | +#include <linux/etherdevice.h> | |
14297 | +#include <linux/ethtool.h> | |
14298 | +#include <linux/mii.h> | |
14299 | +#include <linux/module.h> | |
14300 | +#include <linux/netdevice.h> | |
14301 | +#include <linux/slab.h> | |
14302 | +#include <linux/usb.h> | |
14303 | +#include <linux/usb/usbnet.h> | |
14304 | + | |
14305 | +/* requests */ | |
14306 | +#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ | |
14307 | + USB_RECIP_DEVICE) | |
14308 | +#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ | |
14309 | + USB_RECIP_DEVICE) | |
14310 | +#define MCS7830_RD_BREQ 0x0E | |
14311 | +#define MCS7830_WR_BREQ 0x0D | |
14312 | + | |
14313 | +#define MCS7830_CTRL_TIMEOUT 1000 | |
14314 | +#define MCS7830_MAX_MCAST 64 | |
14315 | + | |
14316 | +#define MCS7830_VENDOR_ID 0x9710 | |
14317 | +#define MCS7832_PRODUCT_ID 0x7832 | |
14318 | +#define MCS7830_PRODUCT_ID 0x7830 | |
14319 | +#define MCS7730_PRODUCT_ID 0x7730 | |
14320 | + | |
14321 | +#define SITECOM_VENDOR_ID 0x0DF6 | |
14322 | +#define LN_030_PRODUCT_ID 0x0021 | |
14323 | + | |
14324 | +#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ | |
14325 | + ADVERTISE_100HALF | ADVERTISE_10FULL | \ | |
14326 | + ADVERTISE_10HALF | ADVERTISE_CSMA) | |
14327 | + | |
14328 | +/* HIF_REG_XX corresponding index value */ | |
14329 | +enum { | |
14330 | + HIF_REG_MULTICAST_HASH = 0x00, | |
14331 | + HIF_REG_PACKET_GAP1 = 0x08, | |
14332 | + HIF_REG_PACKET_GAP2 = 0x09, | |
14333 | + HIF_REG_PHY_DATA = 0x0a, | |
14334 | + HIF_REG_PHY_CMD1 = 0x0c, | |
14335 | + HIF_REG_PHY_CMD1_READ = 0x40, | |
14336 | + HIF_REG_PHY_CMD1_WRITE = 0x20, | |
14337 | + HIF_REG_PHY_CMD1_PHYADDR = 0x01, | |
14338 | + HIF_REG_PHY_CMD2 = 0x0d, | |
14339 | + HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, | |
14340 | + HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, | |
14341 | + HIF_REG_CONFIG = 0x0e, | |
14342 | + /* hmm, spec sez: "R/W", "Except bit 3" (likely TXENABLE). */ | |
14343 | + HIF_REG_CONFIG_CFG = 0x80, | |
14344 | + HIF_REG_CONFIG_SPEED100 = 0x40, | |
14345 | + HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, | |
14346 | + HIF_REG_CONFIG_RXENABLE = 0x10, | |
14347 | + HIF_REG_CONFIG_TXENABLE = 0x08, | |
14348 | + HIF_REG_CONFIG_SLEEPMODE = 0x04, | |
14349 | + HIF_REG_CONFIG_ALLMULTICAST = 0x02, | |
14350 | + HIF_REG_CONFIG_PROMISCUOUS = 0x01, | |
14351 | + HIF_REG_ETHERNET_ADDR = 0x0f, | |
14352 | + HIF_REG_FRAME_DROP_COUNTER = 0x15, /* 0..ff; reset: 0 */ | |
14353 | + HIF_REG_PAUSE_THRESHOLD = 0x16, | |
14354 | + HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, | |
14355 | +}; | |
14356 | + | |
14357 | +/* Trailing status byte in Ethernet Rx frame */ | |
14358 | +enum { | |
14359 | + MCS7830_RX_SHORT_FRAME = 0x01, /* < 64 bytes */ | |
14360 | + MCS7830_RX_LENGTH_ERROR = 0x02, /* framelen != Ethernet length field */ | |
14361 | + MCS7830_RX_ALIGNMENT_ERROR = 0x04, /* non-even number of nibbles */ | |
14362 | + MCS7830_RX_CRC_ERROR = 0x08, | |
14363 | + MCS7830_RX_LARGE_FRAME = 0x10, /* > 1518 bytes */ | |
14364 | + MCS7830_RX_FRAME_CORRECT = 0x20, /* frame is correct */ | |
14365 | + /* [7:6] reserved */ | |
14366 | +}; | |
14367 | + | |
14368 | +struct mcs7830_data { | |
14369 | + u8 multi_filter[8]; | |
14370 | + u8 config; | |
14371 | +}; | |
14372 | + | |
14373 | +static const char driver_name[] = "MOSCHIP usb-ethernet driver"; | |
14374 | + | |
14375 | +static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) | |
14376 | +{ | |
14377 | + return usbnet_read_cmd(dev, MCS7830_RD_BREQ, MCS7830_RD_BMREQ, | |
14378 | + 0x0000, index, data, size); | |
14379 | +} | |
14380 | + | |
14381 | +static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *data) | |
14382 | +{ | |
14383 | + return usbnet_write_cmd(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ, | |
14384 | + 0x0000, index, data, size); | |
14385 | +} | |
14386 | + | |
14387 | +static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) | |
14388 | +{ | |
14389 | + usbnet_write_cmd_async(dev, MCS7830_WR_BREQ, MCS7830_WR_BMREQ, | |
14390 | + 0x0000, index, data, size); | |
14391 | +} | |
14392 | + | |
14393 | +static int mcs7830_hif_get_mac_address(struct usbnet *dev, unsigned char *addr) | |
14394 | +{ | |
14395 | + int ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); | |
14396 | + if (ret < 0) | |
14397 | + return ret; | |
14398 | + return 0; | |
14399 | +} | |
14400 | + | |
14401 | +static int mcs7830_hif_set_mac_address(struct usbnet *dev, unsigned char *addr) | |
14402 | +{ | |
14403 | + int ret = mcs7830_set_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, addr); | |
14404 | + | |
14405 | + if (ret < 0) | |
14406 | + return ret; | |
14407 | + return 0; | |
14408 | +} | |
14409 | + | |
14410 | +static int mcs7830_set_mac_address(struct net_device *netdev, void *p) | |
14411 | +{ | |
14412 | + int ret; | |
14413 | + struct usbnet *dev = netdev_priv(netdev); | |
14414 | + struct sockaddr *addr = p; | |
14415 | + | |
14416 | + if (netif_running(netdev)) | |
14417 | + return -EBUSY; | |
14418 | + | |
14419 | + if (!is_valid_ether_addr(addr->sa_data)) | |
14420 | + return -EADDRNOTAVAIL; | |
14421 | + | |
14422 | + ret = mcs7830_hif_set_mac_address(dev, addr->sa_data); | |
14423 | + | |
14424 | + if (ret < 0) | |
14425 | + return ret; | |
14426 | + | |
14427 | + /* it worked --> adopt it on netdev side */ | |
14428 | + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | |
14429 | + | |
14430 | + return 0; | |
14431 | +} | |
14432 | + | |
14433 | +static int mcs7830_read_phy(struct usbnet *dev, u8 index) | |
14434 | +{ | |
14435 | + int ret; | |
14436 | + int i; | |
14437 | + __le16 val; | |
14438 | + | |
14439 | + u8 cmd[2] = { | |
14440 | + HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, | |
14441 | + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, | |
14442 | + }; | |
14443 | + | |
14444 | + mutex_lock(&dev->phy_mutex); | |
14445 | + /* write the MII command */ | |
14446 | + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | |
14447 | + if (ret < 0) | |
14448 | + goto out; | |
14449 | + | |
14450 | + /* wait for the data to become valid, should be within < 1ms */ | |
14451 | + for (i = 0; i < 10; i++) { | |
14452 | + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | |
14453 | + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | |
14454 | + break; | |
14455 | + ret = -EIO; | |
14456 | + msleep(1); | |
14457 | + } | |
14458 | + if (ret < 0) | |
14459 | + goto out; | |
14460 | + | |
14461 | + /* read actual register contents */ | |
14462 | + ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); | |
14463 | + if (ret < 0) | |
14464 | + goto out; | |
14465 | + ret = le16_to_cpu(val); | |
14466 | + dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", | |
14467 | + index, val, i); | |
14468 | +out: | |
14469 | + mutex_unlock(&dev->phy_mutex); | |
14470 | + return ret; | |
14471 | +} | |
14472 | + | |
14473 | +static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) | |
14474 | +{ | |
14475 | + int ret; | |
14476 | + int i; | |
14477 | + __le16 le_val; | |
14478 | + | |
14479 | + u8 cmd[2] = { | |
14480 | + HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, | |
14481 | + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), | |
14482 | + }; | |
14483 | + | |
14484 | + mutex_lock(&dev->phy_mutex); | |
14485 | + | |
14486 | + /* write the new register contents */ | |
14487 | + le_val = cpu_to_le16(val); | |
14488 | + ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); | |
14489 | + if (ret < 0) | |
14490 | + goto out; | |
14491 | + | |
14492 | + /* write the MII command */ | |
14493 | + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | |
14494 | + if (ret < 0) | |
14495 | + goto out; | |
14496 | + | |
14497 | + /* wait for the command to be accepted by the PHY */ | |
14498 | + for (i = 0; i < 10; i++) { | |
14499 | + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); | |
14500 | + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) | |
14501 | + break; | |
14502 | + ret = -EIO; | |
14503 | + msleep(1); | |
14504 | + } | |
14505 | + if (ret < 0) | |
14506 | + goto out; | |
14507 | + | |
14508 | + ret = 0; | |
14509 | + dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", | |
14510 | + index, val, i); | |
14511 | +out: | |
14512 | + mutex_unlock(&dev->phy_mutex); | |
14513 | + return ret; | |
14514 | +} | |
14515 | + | |
14516 | +/* | |
14517 | + * This algorithm comes from the original mcs7830 version 1.4 driver, | |
14518 | + * not sure if it is needed. | |
14519 | + */ | |
14520 | +static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) | |
14521 | +{ | |
14522 | + int ret; | |
14523 | + /* Enable all media types */ | |
14524 | + ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); | |
14525 | + | |
14526 | + /* First reset BMCR */ | |
14527 | + if (!ret) | |
14528 | + ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); | |
14529 | + /* Enable Auto Neg */ | |
14530 | + if (!ret) | |
14531 | + ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); | |
14532 | + /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ | |
14533 | + if (!ret) | |
14534 | + ret = mcs7830_write_phy(dev, MII_BMCR, | |
14535 | + BMCR_ANENABLE | BMCR_ANRESTART ); | |
14536 | + return ret; | |
14537 | +} | |
14538 | + | |
14539 | + | |
14540 | +/* | |
14541 | + * if we can read register 22, the chip revision is C or higher | |
14542 | + */ | |
14543 | +static int mcs7830_get_rev(struct usbnet *dev) | |
14544 | +{ | |
14545 | + u8 dummy[2]; | |
14546 | + int ret; | |
14547 | + ret = mcs7830_get_reg(dev, HIF_REG_FRAME_DROP_COUNTER, 2, dummy); | |
14548 | + if (ret > 0) | |
14549 | + return 2; /* Rev C or later */ | |
14550 | + return 1; /* earlier revision */ | |
14551 | +} | |
14552 | + | |
14553 | +/* | |
14554 | + * On rev. C we need to set the pause threshold | |
14555 | + */ | |
14556 | +static void mcs7830_rev_C_fixup(struct usbnet *dev) | |
14557 | +{ | |
14558 | + u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; | |
14559 | + int retry; | |
14560 | + | |
14561 | + for (retry = 0; retry < 2; retry++) { | |
14562 | + if (mcs7830_get_rev(dev) == 2) { | |
14563 | + dev_info(&dev->udev->dev, "applying rev.C fixup\n"); | |
14564 | + mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, | |
14565 | + 1, &pause_threshold); | |
14566 | + } | |
14567 | + msleep(1); | |
14568 | + } | |
14569 | +} | |
14570 | + | |
14571 | +static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, | |
14572 | + int location) | |
14573 | +{ | |
14574 | + struct usbnet *dev = netdev_priv(netdev); | |
14575 | + return mcs7830_read_phy(dev, location); | |
14576 | +} | |
14577 | + | |
14578 | +static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, | |
14579 | + int location, int val) | |
14580 | +{ | |
14581 | + struct usbnet *dev = netdev_priv(netdev); | |
14582 | + mcs7830_write_phy(dev, location, val); | |
14583 | +} | |
14584 | + | |
14585 | +static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
14586 | +{ | |
14587 | + struct usbnet *dev = netdev_priv(net); | |
14588 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
14589 | +} | |
14590 | + | |
14591 | +static inline struct mcs7830_data *mcs7830_get_data(struct usbnet *dev) | |
14592 | +{ | |
14593 | + return (struct mcs7830_data *)&dev->data; | |
14594 | +} | |
14595 | + | |
14596 | +static void mcs7830_hif_update_multicast_hash(struct usbnet *dev) | |
14597 | +{ | |
14598 | + struct mcs7830_data *data = mcs7830_get_data(dev); | |
14599 | + mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, | |
14600 | + sizeof data->multi_filter, | |
14601 | + data->multi_filter); | |
14602 | +} | |
14603 | + | |
14604 | +static void mcs7830_hif_update_config(struct usbnet *dev) | |
14605 | +{ | |
14606 | + /* implementation specific to data->config | |
14607 | + (argument needs to be heap-based anyway - USB DMA!) */ | |
14608 | + struct mcs7830_data *data = mcs7830_get_data(dev); | |
14609 | + mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); | |
14610 | +} | |
14611 | + | |
14612 | +static void mcs7830_data_set_multicast(struct net_device *net) | |
14613 | +{ | |
14614 | + struct usbnet *dev = netdev_priv(net); | |
14615 | + struct mcs7830_data *data = mcs7830_get_data(dev); | |
14616 | + | |
14617 | + memset(data->multi_filter, 0, sizeof data->multi_filter); | |
14618 | + | |
14619 | + data->config = HIF_REG_CONFIG_TXENABLE; | |
14620 | + | |
14621 | + /* this should not be needed, but it doesn't work otherwise */ | |
14622 | + data->config |= HIF_REG_CONFIG_ALLMULTICAST; | |
14623 | + | |
14624 | + if (net->flags & IFF_PROMISC) { | |
14625 | + data->config |= HIF_REG_CONFIG_PROMISCUOUS; | |
14626 | + } else if (net->flags & IFF_ALLMULTI || | |
14627 | + netdev_mc_count(net) > MCS7830_MAX_MCAST) { | |
14628 | + data->config |= HIF_REG_CONFIG_ALLMULTICAST; | |
14629 | + } else if (netdev_mc_empty(net)) { | |
14630 | + /* just broadcast and directed */ | |
14631 | + } else { | |
14632 | + /* We use the 20 byte dev->data | |
14633 | + * for our 8 byte filter buffer | |
14634 | + * to avoid allocating memory that | |
14635 | + * is tricky to free later */ | |
14636 | + struct netdev_hw_addr *ha; | |
14637 | + u32 crc_bits; | |
14638 | + | |
14639 | + /* Build the multicast hash filter. */ | |
14640 | + netdev_for_each_mc_addr(ha, net) { | |
14641 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
14642 | + data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); | |
14643 | + } | |
14644 | + } | |
14645 | +} | |
14646 | + | |
14647 | +static int mcs7830_apply_base_config(struct usbnet *dev) | |
14648 | +{ | |
14649 | + int ret; | |
14650 | + | |
14651 | + /* re-configure known MAC (suspend case etc.) */ | |
14652 | + ret = mcs7830_hif_set_mac_address(dev, dev->net->dev_addr); | |
14653 | + if (ret) { | |
14654 | + dev_info(&dev->udev->dev, "Cannot set MAC address\n"); | |
14655 | + goto out; | |
14656 | + } | |
14657 | + | |
14658 | + /* Set up PHY */ | |
14659 | + ret = mcs7830_set_autoneg(dev, 0); | |
14660 | + if (ret) { | |
14661 | + dev_info(&dev->udev->dev, "Cannot set autoneg\n"); | |
14662 | + goto out; | |
14663 | + } | |
14664 | + | |
14665 | + mcs7830_hif_update_multicast_hash(dev); | |
14666 | + mcs7830_hif_update_config(dev); | |
14667 | + | |
14668 | + mcs7830_rev_C_fixup(dev); | |
14669 | + ret = 0; | |
14670 | +out: | |
14671 | + return ret; | |
14672 | +} | |
14673 | + | |
14674 | +/* credits go to asix_set_multicast */ | |
14675 | +static void mcs7830_set_multicast(struct net_device *net) | |
14676 | +{ | |
14677 | + struct usbnet *dev = netdev_priv(net); | |
14678 | + | |
14679 | + mcs7830_data_set_multicast(net); | |
14680 | + | |
14681 | + mcs7830_hif_update_multicast_hash(dev); | |
14682 | + mcs7830_hif_update_config(dev); | |
14683 | +} | |
14684 | + | |
14685 | +static int mcs7830_get_regs_len(struct net_device *net) | |
14686 | +{ | |
14687 | + struct usbnet *dev = netdev_priv(net); | |
14688 | + | |
14689 | + switch (mcs7830_get_rev(dev)) { | |
14690 | + case 1: | |
14691 | + return 21; | |
14692 | + case 2: | |
14693 | + return 32; | |
14694 | + } | |
14695 | + return 0; | |
14696 | +} | |
14697 | + | |
14698 | +static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) | |
14699 | +{ | |
14700 | + usbnet_get_drvinfo(net, drvinfo); | |
14701 | + drvinfo->regdump_len = mcs7830_get_regs_len(net); | |
14702 | +} | |
14703 | + | |
14704 | +static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) | |
14705 | +{ | |
14706 | + struct usbnet *dev = netdev_priv(net); | |
14707 | + | |
14708 | + regs->version = mcs7830_get_rev(dev); | |
14709 | + mcs7830_get_reg(dev, 0, regs->len, data); | |
14710 | +} | |
14711 | + | |
14712 | +static const struct ethtool_ops mcs7830_ethtool_ops = { | |
14713 | + .get_drvinfo = mcs7830_get_drvinfo, | |
14714 | + .get_regs_len = mcs7830_get_regs_len, | |
14715 | + .get_regs = mcs7830_get_regs, | |
14716 | + | |
14717 | + /* common usbnet calls */ | |
14718 | + .get_link = usbnet_get_link, | |
14719 | + .get_msglevel = usbnet_get_msglevel, | |
14720 | + .set_msglevel = usbnet_set_msglevel, | |
14721 | + .get_settings = usbnet_get_settings, | |
14722 | + .set_settings = usbnet_set_settings, | |
14723 | + .nway_reset = usbnet_nway_reset, | |
14724 | +}; | |
14725 | + | |
14726 | +static const struct net_device_ops mcs7830_netdev_ops = { | |
14727 | + .ndo_open = usbnet_open, | |
14728 | + .ndo_stop = usbnet_stop, | |
14729 | + .ndo_start_xmit = usbnet_start_xmit, | |
14730 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
14731 | + .ndo_change_mtu = usbnet_change_mtu, | |
14732 | + .ndo_validate_addr = eth_validate_addr, | |
14733 | + .ndo_do_ioctl = mcs7830_ioctl, | |
14734 | + .ndo_set_rx_mode = mcs7830_set_multicast, | |
14735 | + .ndo_set_mac_address = mcs7830_set_mac_address, | |
14736 | +}; | |
14737 | + | |
14738 | +static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) | |
14739 | +{ | |
14740 | + struct net_device *net = dev->net; | |
14741 | + int ret; | |
14742 | + int retry; | |
14743 | + | |
14744 | + /* Initial startup: Gather MAC address setting from EEPROM */ | |
14745 | + ret = -EINVAL; | |
14746 | + for (retry = 0; retry < 5 && ret; retry++) | |
14747 | + ret = mcs7830_hif_get_mac_address(dev, net->dev_addr); | |
14748 | + if (ret) { | |
14749 | + dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); | |
14750 | + goto out; | |
14751 | + } | |
14752 | + | |
14753 | + mcs7830_data_set_multicast(net); | |
14754 | + | |
14755 | + ret = mcs7830_apply_base_config(dev); | |
14756 | + if (ret) | |
14757 | + goto out; | |
14758 | + | |
14759 | + net->ethtool_ops = &mcs7830_ethtool_ops; | |
14760 | + net->netdev_ops = &mcs7830_netdev_ops; | |
14761 | + | |
14762 | + /* reserve space for the status byte on rx */ | |
14763 | + dev->rx_urb_size = ETH_FRAME_LEN + 1; | |
14764 | + | |
14765 | + dev->mii.mdio_read = mcs7830_mdio_read; | |
14766 | + dev->mii.mdio_write = mcs7830_mdio_write; | |
14767 | + dev->mii.dev = net; | |
14768 | + dev->mii.phy_id_mask = 0x3f; | |
14769 | + dev->mii.reg_num_mask = 0x1f; | |
14770 | + dev->mii.phy_id = *((u8 *) net->dev_addr + 1); | |
14771 | + | |
14772 | + ret = usbnet_get_endpoints(dev, udev); | |
14773 | +out: | |
14774 | + return ret; | |
14775 | +} | |
14776 | + | |
14777 | +/* The chip always appends a status byte that we need to strip */ | |
14778 | +static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
14779 | +{ | |
14780 | + u8 status; | |
14781 | + | |
14782 | + /* This check is no longer done by usbnet */ | |
14783 | + if (skb->len < dev->net->hard_header_len) { | |
14784 | + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); | |
14785 | + return 0; | |
14786 | + } | |
14787 | + | |
14788 | + skb_trim(skb, skb->len - 1); | |
14789 | + status = skb->data[skb->len]; | |
14790 | + | |
14791 | + if (status != MCS7830_RX_FRAME_CORRECT) { | |
14792 | + dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); | |
14793 | + | |
14794 | + /* hmm, perhaps usbnet.c already sees a globally visible | |
14795 | + frame error and increments rx_errors on its own already? */ | |
14796 | + dev->net->stats.rx_errors++; | |
14797 | + | |
14798 | + if (status & (MCS7830_RX_SHORT_FRAME | |
14799 | + |MCS7830_RX_LENGTH_ERROR | |
14800 | + |MCS7830_RX_LARGE_FRAME)) | |
14801 | + dev->net->stats.rx_length_errors++; | |
14802 | + if (status & MCS7830_RX_ALIGNMENT_ERROR) | |
14803 | + dev->net->stats.rx_frame_errors++; | |
14804 | + if (status & MCS7830_RX_CRC_ERROR) | |
14805 | + dev->net->stats.rx_crc_errors++; | |
14806 | + } | |
14807 | + | |
14808 | + return skb->len > 0; | |
14809 | +} | |
14810 | + | |
14811 | +static void mcs7830_status(struct usbnet *dev, struct urb *urb) | |
14812 | +{ | |
14813 | + u8 *buf = urb->transfer_buffer; | |
14814 | + bool link, link_changed; | |
14815 | + | |
14816 | + if (urb->actual_length < 16) | |
14817 | + return; | |
14818 | + | |
14819 | + link = !(buf[1] == 0x20); | |
14820 | + link_changed = netif_carrier_ok(dev->net) != link; | |
14821 | + if (link_changed) { | |
14822 | + usbnet_link_change(dev, link, 0); | |
14823 | + netdev_dbg(dev->net, "Link Status is: %d\n", link); | |
14824 | + } | |
14825 | +} | |
14826 | + | |
14827 | +static const struct driver_info moschip_info = { | |
14828 | + .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", | |
14829 | + .bind = mcs7830_bind, | |
14830 | + .rx_fixup = mcs7830_rx_fixup, | |
14831 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
14832 | + .status = mcs7830_status, | |
14833 | + .in = 1, | |
14834 | + .out = 2, | |
14835 | +}; | |
14836 | + | |
14837 | +static const struct driver_info sitecom_info = { | |
14838 | + .description = "Sitecom LN-30 usb-NET adapter", | |
14839 | + .bind = mcs7830_bind, | |
14840 | + .rx_fixup = mcs7830_rx_fixup, | |
14841 | + .flags = FLAG_ETHER | FLAG_LINK_INTR, | |
14842 | + .status = mcs7830_status, | |
14843 | + .in = 1, | |
14844 | + .out = 2, | |
14845 | +}; | |
14846 | + | |
14847 | +static const struct usb_device_id products[] = { | |
14848 | + { | |
14849 | + USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID), | |
14850 | + .driver_info = (unsigned long) &moschip_info, | |
14851 | + }, | |
14852 | + { | |
14853 | + USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), | |
14854 | + .driver_info = (unsigned long) &moschip_info, | |
14855 | + }, | |
14856 | + { | |
14857 | + USB_DEVICE(MCS7830_VENDOR_ID, MCS7730_PRODUCT_ID), | |
14858 | + .driver_info = (unsigned long) &moschip_info, | |
14859 | + }, | |
14860 | + { | |
14861 | + USB_DEVICE(SITECOM_VENDOR_ID, LN_030_PRODUCT_ID), | |
14862 | + .driver_info = (unsigned long) &sitecom_info, | |
14863 | + }, | |
14864 | + {}, | |
14865 | +}; | |
14866 | +MODULE_DEVICE_TABLE(usb, products); | |
14867 | + | |
14868 | +static int mcs7830_reset_resume (struct usb_interface *intf) | |
14869 | +{ | |
14870 | + /* YES, this function is successful enough that ethtool -d | |
14871 | + does show same output pre-/post-suspend */ | |
14872 | + | |
14873 | + struct usbnet *dev = usb_get_intfdata(intf); | |
14874 | + | |
14875 | + mcs7830_apply_base_config(dev); | |
14876 | + | |
14877 | + usbnet_resume(intf); | |
14878 | + | |
14879 | + return 0; | |
14880 | +} | |
14881 | + | |
14882 | +static struct usb_driver mcs7830_driver = { | |
14883 | + .name = driver_name, | |
14884 | + .id_table = products, | |
14885 | + .probe = usbnet_probe, | |
14886 | + .disconnect = usbnet_disconnect, | |
14887 | + .suspend = usbnet_suspend, | |
14888 | + .resume = usbnet_resume, | |
14889 | + .reset_resume = mcs7830_reset_resume, | |
14890 | + .disable_hub_initiated_lpm = 1, | |
14891 | +}; | |
14892 | + | |
14893 | +module_usb_driver(mcs7830_driver); | |
14894 | + | |
14895 | +MODULE_DESCRIPTION("USB to network adapter MCS7830)"); | |
14896 | +MODULE_LICENSE("GPL"); | |
14897 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/net1080.c backports-3.18.1-1/drivers/net/usb/net1080.c | |
14898 | --- backports-3.18.1-1.org/drivers/net/usb/net1080.c 1970-01-01 01:00:00.000000000 +0100 | |
14899 | +++ backports-3.18.1-1/drivers/net/usb/net1080.c 2014-12-16 18:39:45.000000000 +0100 | |
14900 | @@ -0,0 +1,544 @@ | |
14901 | +/* | |
14902 | + * Net1080 based USB host-to-host cables | |
14903 | + * Copyright (C) 2000-2005 by David Brownell | |
14904 | + * | |
14905 | + * This program is free software; you can redistribute it and/or modify | |
14906 | + * it under the terms of the GNU General Public License as published by | |
14907 | + * the Free Software Foundation; either version 2 of the License, or | |
14908 | + * (at your option) any later version. | |
14909 | + * | |
14910 | + * This program is distributed in the hope that it will be useful, | |
14911 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14912 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14913 | + * GNU General Public License for more details. | |
14914 | + * | |
14915 | + * You should have received a copy of the GNU General Public License | |
14916 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
14917 | + */ | |
14918 | + | |
14919 | +// #define DEBUG // error path messages, extra info | |
14920 | +// #define VERBOSE // more; success messages | |
14921 | + | |
14922 | +#include <linux/module.h> | |
14923 | +#include <linux/netdevice.h> | |
14924 | +#include <linux/etherdevice.h> | |
14925 | +#include <linux/ethtool.h> | |
14926 | +#include <linux/workqueue.h> | |
14927 | +#include <linux/mii.h> | |
14928 | +#include <linux/usb.h> | |
14929 | +#include <linux/usb/usbnet.h> | |
14930 | +#include <linux/slab.h> | |
14931 | + | |
14932 | +#include <asm/unaligned.h> | |
14933 | + | |
14934 | + | |
14935 | +/* | |
14936 | + * Netchip 1080 driver ... http://www.netchip.com | |
14937 | + * (Sept 2004: End-of-life announcement has been sent.) | |
14938 | + * Used in (some) LapLink cables | |
14939 | + */ | |
14940 | + | |
14941 | +#define frame_errors data[1] | |
14942 | + | |
14943 | +/* | |
14944 | + * NetChip framing of ethernet packets, supporting additional error | |
14945 | + * checks for links that may drop bulk packets from inside messages. | |
14946 | + * Odd USB length == always short read for last usb packet. | |
14947 | + * - nc_header | |
14948 | + * - Ethernet header (14 bytes) | |
14949 | + * - payload | |
14950 | + * - (optional padding byte, if needed so length becomes odd) | |
14951 | + * - nc_trailer | |
14952 | + * | |
14953 | + * This framing is to be avoided for non-NetChip devices. | |
14954 | + */ | |
14955 | + | |
14956 | +struct nc_header { // packed: | |
14957 | + __le16 hdr_len; // sizeof nc_header (LE, all) | |
14958 | + __le16 packet_len; // payload size (including ethhdr) | |
14959 | + __le16 packet_id; // detects dropped packets | |
14960 | +#define MIN_HEADER 6 | |
14961 | + | |
14962 | + // all else is optional, and must start with: | |
14963 | + // __le16 vendorId; // from usb-if | |
14964 | + // __le16 productId; | |
14965 | +} __packed; | |
14966 | + | |
14967 | +#define PAD_BYTE ((unsigned char)0xAC) | |
14968 | + | |
14969 | +struct nc_trailer { | |
14970 | + __le16 packet_id; | |
14971 | +} __packed; | |
14972 | + | |
14973 | +// packets may use FLAG_FRAMING_NC and optional pad | |
14974 | +#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ | |
14975 | + + sizeof (struct ethhdr) \ | |
14976 | + + (mtu) \ | |
14977 | + + 1 \ | |
14978 | + + sizeof (struct nc_trailer)) | |
14979 | + | |
14980 | +#define MIN_FRAMED FRAMED_SIZE(0) | |
14981 | + | |
14982 | +/* packets _could_ be up to 64KB... */ | |
14983 | +#define NC_MAX_PACKET 32767 | |
14984 | + | |
14985 | + | |
14986 | +/* | |
14987 | + * Zero means no timeout; else, how long a 64 byte bulk packet may be queued | |
14988 | + * before the hardware drops it. If that's done, the driver will need to | |
14989 | + * frame network packets to guard against the dropped USB packets. The win32 | |
14990 | + * driver sets this for both sides of the link. | |
14991 | + */ | |
14992 | +#define NC_READ_TTL_MS ((u8)255) // ms | |
14993 | + | |
14994 | +/* | |
14995 | + * We ignore most registers and EEPROM contents. | |
14996 | + */ | |
14997 | +#define REG_USBCTL ((u8)0x04) | |
14998 | +#define REG_TTL ((u8)0x10) | |
14999 | +#define REG_STATUS ((u8)0x11) | |
15000 | + | |
15001 | +/* | |
15002 | + * Vendor specific requests to read/write data | |
15003 | + */ | |
15004 | +#define REQUEST_REGISTER ((u8)0x10) | |
15005 | +#define REQUEST_EEPROM ((u8)0x11) | |
15006 | + | |
15007 | +static int | |
15008 | +nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr) | |
15009 | +{ | |
15010 | + int status = usbnet_read_cmd(dev, req, | |
15011 | + USB_DIR_IN | USB_TYPE_VENDOR | | |
15012 | + USB_RECIP_DEVICE, | |
15013 | + 0, regnum, retval_ptr, | |
15014 | + sizeof *retval_ptr); | |
15015 | + if (status > 0) | |
15016 | + status = 0; | |
15017 | + if (!status) | |
15018 | + le16_to_cpus(retval_ptr); | |
15019 | + return status; | |
15020 | +} | |
15021 | + | |
15022 | +static inline int | |
15023 | +nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr) | |
15024 | +{ | |
15025 | + return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr); | |
15026 | +} | |
15027 | + | |
15028 | +// no retval ... can become async, usable in_interrupt() | |
15029 | +static void | |
15030 | +nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value) | |
15031 | +{ | |
15032 | + usbnet_write_cmd(dev, req, | |
15033 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
15034 | + value, regnum, NULL, 0); | |
15035 | +} | |
15036 | + | |
15037 | +static inline void | |
15038 | +nc_register_write(struct usbnet *dev, u8 regnum, u16 value) | |
15039 | +{ | |
15040 | + nc_vendor_write(dev, REQUEST_REGISTER, regnum, value); | |
15041 | +} | |
15042 | + | |
15043 | + | |
15044 | +#if 0 | |
15045 | +static void nc_dump_registers(struct usbnet *dev) | |
15046 | +{ | |
15047 | + u8 reg; | |
15048 | + u16 *vp = kmalloc(sizeof (u16)); | |
15049 | + | |
15050 | + if (!vp) | |
15051 | + return; | |
15052 | + | |
15053 | + netdev_dbg(dev->net, "registers:\n"); | |
15054 | + for (reg = 0; reg < 0x20; reg++) { | |
15055 | + int retval; | |
15056 | + | |
15057 | + // reading some registers is trouble | |
15058 | + if (reg >= 0x08 && reg <= 0xf) | |
15059 | + continue; | |
15060 | + if (reg >= 0x12 && reg <= 0x1e) | |
15061 | + continue; | |
15062 | + | |
15063 | + retval = nc_register_read(dev, reg, vp); | |
15064 | + if (retval < 0) | |
15065 | + netdev_dbg(dev->net, "reg [0x%x] ==> error %d\n", | |
15066 | + reg, retval); | |
15067 | + else | |
15068 | + netdev_dbg(dev->net, "reg [0x%x] = 0x%x\n", reg, *vp); | |
15069 | + } | |
15070 | + kfree(vp); | |
15071 | +} | |
15072 | +#endif | |
15073 | + | |
15074 | + | |
15075 | +/*-------------------------------------------------------------------------*/ | |
15076 | + | |
15077 | +/* | |
15078 | + * Control register | |
15079 | + */ | |
15080 | + | |
15081 | +#define USBCTL_WRITABLE_MASK 0x1f0f | |
15082 | +// bits 15-13 reserved, r/o | |
15083 | +#define USBCTL_ENABLE_LANG (1 << 12) | |
15084 | +#define USBCTL_ENABLE_MFGR (1 << 11) | |
15085 | +#define USBCTL_ENABLE_PROD (1 << 10) | |
15086 | +#define USBCTL_ENABLE_SERIAL (1 << 9) | |
15087 | +#define USBCTL_ENABLE_DEFAULTS (1 << 8) | |
15088 | +// bits 7-4 reserved, r/o | |
15089 | +#define USBCTL_FLUSH_OTHER (1 << 3) | |
15090 | +#define USBCTL_FLUSH_THIS (1 << 2) | |
15091 | +#define USBCTL_DISCONN_OTHER (1 << 1) | |
15092 | +#define USBCTL_DISCONN_THIS (1 << 0) | |
15093 | + | |
15094 | +static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) | |
15095 | +{ | |
15096 | + netif_dbg(dev, link, dev->net, | |
15097 | + "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n", | |
15098 | + dev->udev->bus->bus_name, dev->udev->devpath, | |
15099 | + usbctl, | |
15100 | + (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", | |
15101 | + (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", | |
15102 | + (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", | |
15103 | + (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", | |
15104 | + (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", | |
15105 | + | |
15106 | + (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", | |
15107 | + (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", | |
15108 | + | |
15109 | + (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", | |
15110 | + (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", | |
15111 | + | |
15112 | + usbctl & ~USBCTL_WRITABLE_MASK); | |
15113 | +} | |
15114 | + | |
15115 | +/*-------------------------------------------------------------------------*/ | |
15116 | + | |
15117 | +/* | |
15118 | + * Status register | |
15119 | + */ | |
15120 | + | |
15121 | +#define STATUS_PORT_A (1 << 15) | |
15122 | + | |
15123 | +#define STATUS_CONN_OTHER (1 << 14) | |
15124 | +#define STATUS_SUSPEND_OTHER (1 << 13) | |
15125 | +#define STATUS_MAILBOX_OTHER (1 << 12) | |
15126 | +#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03) | |
15127 | + | |
15128 | +#define STATUS_CONN_THIS (1 << 6) | |
15129 | +#define STATUS_SUSPEND_THIS (1 << 5) | |
15130 | +#define STATUS_MAILBOX_THIS (1 << 4) | |
15131 | +#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03) | |
15132 | + | |
15133 | +#define STATUS_UNSPEC_MASK 0x0c8c | |
15134 | +#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) | |
15135 | + | |
15136 | + | |
15137 | +static inline void nc_dump_status(struct usbnet *dev, u16 status) | |
15138 | +{ | |
15139 | + netif_dbg(dev, link, dev->net, | |
15140 | + "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n", | |
15141 | + dev->udev->bus->bus_name, dev->udev->devpath, | |
15142 | + status, | |
15143 | + | |
15144 | + // XXX the packet counts don't seem right | |
15145 | + // (1 at reset, not 0); maybe UNSPEC too | |
15146 | + | |
15147 | + (status & STATUS_PORT_A) ? 'A' : 'B', | |
15148 | + STATUS_PACKETS_THIS(status), | |
15149 | + (status & STATUS_CONN_THIS) ? " CON" : "", | |
15150 | + (status & STATUS_SUSPEND_THIS) ? " SUS" : "", | |
15151 | + (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", | |
15152 | + | |
15153 | + STATUS_PACKETS_OTHER(status), | |
15154 | + (status & STATUS_CONN_OTHER) ? " CON" : "", | |
15155 | + (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", | |
15156 | + (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", | |
15157 | + | |
15158 | + status & STATUS_UNSPEC_MASK); | |
15159 | +} | |
15160 | + | |
15161 | +/*-------------------------------------------------------------------------*/ | |
15162 | + | |
15163 | +/* | |
15164 | + * TTL register | |
15165 | + */ | |
15166 | + | |
15167 | +#define TTL_THIS(ttl) (0x00ff & ttl) | |
15168 | +#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) | |
15169 | +#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) | |
15170 | + | |
15171 | +static inline void nc_dump_ttl(struct usbnet *dev, u16 ttl) | |
15172 | +{ | |
15173 | + netif_dbg(dev, link, dev->net, "net1080 %s-%s ttl 0x%x this = %d, other = %d\n", | |
15174 | + dev->udev->bus->bus_name, dev->udev->devpath, | |
15175 | + ttl, TTL_THIS(ttl), TTL_OTHER(ttl)); | |
15176 | +} | |
15177 | + | |
15178 | +/*-------------------------------------------------------------------------*/ | |
15179 | + | |
15180 | +static int net1080_reset(struct usbnet *dev) | |
15181 | +{ | |
15182 | + u16 usbctl, status, ttl; | |
15183 | + u16 vp; | |
15184 | + int retval; | |
15185 | + | |
15186 | + // nc_dump_registers(dev); | |
15187 | + | |
15188 | + if ((retval = nc_register_read(dev, REG_STATUS, &vp)) < 0) { | |
15189 | + netdev_dbg(dev->net, "can't read %s-%s status: %d\n", | |
15190 | + dev->udev->bus->bus_name, dev->udev->devpath, retval); | |
15191 | + goto done; | |
15192 | + } | |
15193 | + status = vp; | |
15194 | + nc_dump_status(dev, status); | |
15195 | + | |
15196 | + if ((retval = nc_register_read(dev, REG_USBCTL, &vp)) < 0) { | |
15197 | + netdev_dbg(dev->net, "can't read USBCTL, %d\n", retval); | |
15198 | + goto done; | |
15199 | + } | |
15200 | + usbctl = vp; | |
15201 | + nc_dump_usbctl(dev, usbctl); | |
15202 | + | |
15203 | + nc_register_write(dev, REG_USBCTL, | |
15204 | + USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); | |
15205 | + | |
15206 | + if ((retval = nc_register_read(dev, REG_TTL, &vp)) < 0) { | |
15207 | + netdev_dbg(dev->net, "can't read TTL, %d\n", retval); | |
15208 | + goto done; | |
15209 | + } | |
15210 | + ttl = vp; | |
15211 | + // nc_dump_ttl(dev, ttl); | |
15212 | + | |
15213 | + nc_register_write(dev, REG_TTL, | |
15214 | + MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) ); | |
15215 | + netdev_dbg(dev->net, "assigned TTL, %d ms\n", NC_READ_TTL_MS); | |
15216 | + | |
15217 | + netif_info(dev, link, dev->net, "port %c, peer %sconnected\n", | |
15218 | + (status & STATUS_PORT_A) ? 'A' : 'B', | |
15219 | + (status & STATUS_CONN_OTHER) ? "" : "dis"); | |
15220 | + retval = 0; | |
15221 | + | |
15222 | +done: | |
15223 | + return retval; | |
15224 | +} | |
15225 | + | |
15226 | +static int net1080_check_connect(struct usbnet *dev) | |
15227 | +{ | |
15228 | + int retval; | |
15229 | + u16 status; | |
15230 | + u16 vp; | |
15231 | + | |
15232 | + retval = nc_register_read(dev, REG_STATUS, &vp); | |
15233 | + status = vp; | |
15234 | + if (retval != 0) { | |
15235 | + netdev_dbg(dev->net, "net1080_check_conn read - %d\n", retval); | |
15236 | + return retval; | |
15237 | + } | |
15238 | + if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) | |
15239 | + return -ENOLINK; | |
15240 | + return 0; | |
15241 | +} | |
15242 | + | |
15243 | +static void nc_ensure_sync(struct usbnet *dev) | |
15244 | +{ | |
15245 | + if (++dev->frame_errors <= 5) | |
15246 | + return; | |
15247 | + | |
15248 | + if (usbnet_write_cmd_async(dev, REQUEST_REGISTER, | |
15249 | + USB_DIR_OUT | USB_TYPE_VENDOR | | |
15250 | + USB_RECIP_DEVICE, | |
15251 | + USBCTL_FLUSH_THIS | | |
15252 | + USBCTL_FLUSH_OTHER, | |
15253 | + REG_USBCTL, NULL, 0)) | |
15254 | + return; | |
15255 | + | |
15256 | + netif_dbg(dev, rx_err, dev->net, | |
15257 | + "flush net1080; too many framing errors\n"); | |
15258 | + dev->frame_errors = 0; | |
15259 | +} | |
15260 | + | |
15261 | +static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
15262 | +{ | |
15263 | + struct nc_header *header; | |
15264 | + struct nc_trailer *trailer; | |
15265 | + u16 hdr_len, packet_len; | |
15266 | + | |
15267 | + /* This check is no longer done by usbnet */ | |
15268 | + if (skb->len < dev->net->hard_header_len) | |
15269 | + return 0; | |
15270 | + | |
15271 | + if (!(skb->len & 0x01)) { | |
15272 | + netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n", | |
15273 | + skb->len, dev->net->hard_header_len, dev->hard_mtu, | |
15274 | + dev->net->mtu); | |
15275 | + dev->net->stats.rx_frame_errors++; | |
15276 | + nc_ensure_sync(dev); | |
15277 | + return 0; | |
15278 | + } | |
15279 | + | |
15280 | + header = (struct nc_header *) skb->data; | |
15281 | + hdr_len = le16_to_cpup(&header->hdr_len); | |
15282 | + packet_len = le16_to_cpup(&header->packet_len); | |
15283 | + if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) { | |
15284 | + dev->net->stats.rx_frame_errors++; | |
15285 | + netdev_dbg(dev->net, "packet too big, %d\n", packet_len); | |
15286 | + nc_ensure_sync(dev); | |
15287 | + return 0; | |
15288 | + } else if (hdr_len < MIN_HEADER) { | |
15289 | + dev->net->stats.rx_frame_errors++; | |
15290 | + netdev_dbg(dev->net, "header too short, %d\n", hdr_len); | |
15291 | + nc_ensure_sync(dev); | |
15292 | + return 0; | |
15293 | + } else if (hdr_len > MIN_HEADER) { | |
15294 | + // out of band data for us? | |
15295 | + netdev_dbg(dev->net, "header OOB, %d bytes\n", hdr_len - MIN_HEADER); | |
15296 | + nc_ensure_sync(dev); | |
15297 | + // switch (vendor/product ids) { ... } | |
15298 | + } | |
15299 | + skb_pull(skb, hdr_len); | |
15300 | + | |
15301 | + trailer = (struct nc_trailer *) | |
15302 | + (skb->data + skb->len - sizeof *trailer); | |
15303 | + skb_trim(skb, skb->len - sizeof *trailer); | |
15304 | + | |
15305 | + if ((packet_len & 0x01) == 0) { | |
15306 | + if (skb->data [packet_len] != PAD_BYTE) { | |
15307 | + dev->net->stats.rx_frame_errors++; | |
15308 | + netdev_dbg(dev->net, "bad pad\n"); | |
15309 | + return 0; | |
15310 | + } | |
15311 | + skb_trim(skb, skb->len - 1); | |
15312 | + } | |
15313 | + if (skb->len != packet_len) { | |
15314 | + dev->net->stats.rx_frame_errors++; | |
15315 | + netdev_dbg(dev->net, "bad packet len %d (expected %d)\n", | |
15316 | + skb->len, packet_len); | |
15317 | + nc_ensure_sync(dev); | |
15318 | + return 0; | |
15319 | + } | |
15320 | + if (header->packet_id != get_unaligned(&trailer->packet_id)) { | |
15321 | + dev->net->stats.rx_fifo_errors++; | |
15322 | + netdev_dbg(dev->net, "(2+ dropped) rx packet_id mismatch 0x%x 0x%x\n", | |
15323 | + le16_to_cpu(header->packet_id), | |
15324 | + le16_to_cpu(trailer->packet_id)); | |
15325 | + return 0; | |
15326 | + } | |
15327 | +#if 0 | |
15328 | + netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", header->hdr_len, | |
15329 | + header->packet_len, header->packet_id); | |
15330 | +#endif | |
15331 | + dev->frame_errors = 0; | |
15332 | + return 1; | |
15333 | +} | |
15334 | + | |
15335 | +static struct sk_buff * | |
15336 | +net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |
15337 | +{ | |
15338 | + struct sk_buff *skb2; | |
15339 | + struct nc_header *header = NULL; | |
15340 | + struct nc_trailer *trailer = NULL; | |
15341 | + int padlen = sizeof (struct nc_trailer); | |
15342 | + int len = skb->len; | |
15343 | + | |
15344 | + if (!((len + padlen + sizeof (struct nc_header)) & 0x01)) | |
15345 | + padlen++; | |
15346 | + if (!skb_cloned(skb)) { | |
15347 | + int headroom = skb_headroom(skb); | |
15348 | + int tailroom = skb_tailroom(skb); | |
15349 | + | |
15350 | + if (padlen <= tailroom && | |
15351 | + sizeof(struct nc_header) <= headroom) | |
15352 | + /* There's enough head and tail room */ | |
15353 | + goto encapsulate; | |
15354 | + | |
15355 | + if ((sizeof (struct nc_header) + padlen) < | |
15356 | + (headroom + tailroom)) { | |
15357 | + /* There's enough total room, so just readjust */ | |
15358 | + skb->data = memmove(skb->head | |
15359 | + + sizeof (struct nc_header), | |
15360 | + skb->data, skb->len); | |
15361 | + skb_set_tail_pointer(skb, len); | |
15362 | + goto encapsulate; | |
15363 | + } | |
15364 | + } | |
15365 | + | |
15366 | + /* Create a new skb to use with the correct size */ | |
15367 | + skb2 = skb_copy_expand(skb, | |
15368 | + sizeof (struct nc_header), | |
15369 | + padlen, | |
15370 | + flags); | |
15371 | + dev_kfree_skb_any(skb); | |
15372 | + if (!skb2) | |
15373 | + return skb2; | |
15374 | + skb = skb2; | |
15375 | + | |
15376 | +encapsulate: | |
15377 | + /* header first */ | |
15378 | + header = (struct nc_header *) skb_push(skb, sizeof *header); | |
15379 | + header->hdr_len = cpu_to_le16(sizeof (*header)); | |
15380 | + header->packet_len = cpu_to_le16(len); | |
15381 | + header->packet_id = cpu_to_le16((u16)dev->xid++); | |
15382 | + | |
15383 | + /* maybe pad; then trailer */ | |
15384 | + if (!((skb->len + sizeof *trailer) & 0x01)) | |
15385 | + *skb_put(skb, 1) = PAD_BYTE; | |
15386 | + trailer = (struct nc_trailer *) skb_put(skb, sizeof *trailer); | |
15387 | + put_unaligned(header->packet_id, &trailer->packet_id); | |
15388 | +#if 0 | |
15389 | + netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n", | |
15390 | + header->hdr_len, header->packet_len, | |
15391 | + header->packet_id); | |
15392 | +#endif | |
15393 | + return skb; | |
15394 | +} | |
15395 | + | |
15396 | +static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) | |
15397 | +{ | |
15398 | + unsigned extra = sizeof (struct nc_header) | |
15399 | + + 1 | |
15400 | + + sizeof (struct nc_trailer); | |
15401 | + | |
15402 | + dev->net->hard_header_len += extra; | |
15403 | + dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; | |
15404 | + dev->hard_mtu = NC_MAX_PACKET; | |
15405 | + return usbnet_get_endpoints (dev, intf); | |
15406 | +} | |
15407 | + | |
15408 | +static const struct driver_info net1080_info = { | |
15409 | + .description = "NetChip TurboCONNECT", | |
15410 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC, | |
15411 | + .bind = net1080_bind, | |
15412 | + .reset = net1080_reset, | |
15413 | + .check_connect = net1080_check_connect, | |
15414 | + .rx_fixup = net1080_rx_fixup, | |
15415 | + .tx_fixup = net1080_tx_fixup, | |
15416 | +}; | |
15417 | + | |
15418 | +static const struct usb_device_id products [] = { | |
15419 | +{ | |
15420 | + USB_DEVICE(0x0525, 0x1080), // NetChip ref design | |
15421 | + .driver_info = (unsigned long) &net1080_info, | |
15422 | +}, { | |
15423 | + USB_DEVICE(0x06D0, 0x0622), // Laplink Gold | |
15424 | + .driver_info = (unsigned long) &net1080_info, | |
15425 | +}, | |
15426 | + { }, // END | |
15427 | +}; | |
15428 | +MODULE_DEVICE_TABLE(usb, products); | |
15429 | + | |
15430 | +static struct usb_driver net1080_driver = { | |
15431 | + .name = "net1080", | |
15432 | + .id_table = products, | |
15433 | + .probe = usbnet_probe, | |
15434 | + .disconnect = usbnet_disconnect, | |
15435 | + .suspend = usbnet_suspend, | |
15436 | + .resume = usbnet_resume, | |
15437 | + .disable_hub_initiated_lpm = 1, | |
15438 | +}; | |
15439 | + | |
15440 | +module_usb_driver(net1080_driver); | |
15441 | + | |
15442 | +MODULE_AUTHOR("David Brownell"); | |
15443 | +MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links"); | |
15444 | +MODULE_LICENSE("GPL"); | |
15445 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/pegasus.c backports-3.18.1-1/drivers/net/usb/pegasus.c | |
15446 | --- backports-3.18.1-1.org/drivers/net/usb/pegasus.c 1970-01-01 01:00:00.000000000 +0100 | |
15447 | +++ backports-3.18.1-1/drivers/net/usb/pegasus.c 2014-12-16 18:39:45.000000000 +0100 | |
15448 | @@ -0,0 +1,1335 @@ | |
15449 | +/* | |
15450 | + * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) | |
15451 | + * | |
15452 | + * This program is free software; you can redistribute it and/or modify | |
15453 | + * it under the terms of the GNU General Public License version 2 as | |
15454 | + * published by the Free Software Foundation. | |
15455 | + * | |
15456 | + * ChangeLog: | |
15457 | + * .... Most of the time spent on reading sources & docs. | |
15458 | + * v0.2.x First official release for the Linux kernel. | |
15459 | + * v0.3.0 Beutified and structured, some bugs fixed. | |
15460 | + * v0.3.x URBifying bulk requests and bugfixing. First relatively | |
15461 | + * stable release. Still can touch device's registers only | |
15462 | + * from top-halves. | |
15463 | + * v0.4.0 Control messages remained unurbified are now URBs. | |
15464 | + * Now we can touch the HW at any time. | |
15465 | + * v0.4.9 Control urbs again use process context to wait. Argh... | |
15466 | + * Some long standing bugs (enable_net_traffic) fixed. | |
15467 | + * Also nasty trick about resubmiting control urb from | |
15468 | + * interrupt context used. Please let me know how it | |
15469 | + * behaves. Pegasus II support added since this version. | |
15470 | + * TODO: suppressing HCD warnings spewage on disconnect. | |
15471 | + * v0.4.13 Ethernet address is now set at probe(), not at open() | |
15472 | + * time as this seems to break dhcpd. | |
15473 | + * v0.5.0 branch to 2.5.x kernels | |
15474 | + * v0.5.1 ethtool support added | |
15475 | + * v0.5.5 rx socket buffers are in a pool and the their allocation | |
15476 | + * is out of the interrupt routine. | |
15477 | + * ... | |
15478 | + * v0.9.3 simplified [get|set]_register(s), async update registers | |
15479 | + * logic revisited, receive skb_pool removed. | |
15480 | + */ | |
15481 | + | |
15482 | +#include <linux/sched.h> | |
15483 | +#include <linux/slab.h> | |
15484 | +#include <linux/init.h> | |
15485 | +#include <linux/delay.h> | |
15486 | +#include <linux/netdevice.h> | |
15487 | +#include <linux/etherdevice.h> | |
15488 | +#include <linux/ethtool.h> | |
15489 | +#include <linux/mii.h> | |
15490 | +#include <linux/usb.h> | |
15491 | +#include <linux/module.h> | |
15492 | +#include <asm/byteorder.h> | |
15493 | +#include <asm/uaccess.h> | |
15494 | +#include "pegasus.h" | |
15495 | + | |
15496 | +/* | |
15497 | + * Version Information | |
15498 | + */ | |
15499 | +#define DRIVER_VERSION "v0.9.3 (2013/04/25)" | |
15500 | +#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>" | |
15501 | +#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" | |
15502 | + | |
15503 | +static const char driver_name[] = "pegasus"; | |
15504 | + | |
15505 | +#undef PEGASUS_WRITE_EEPROM | |
15506 | +#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \ | |
15507 | + BMSR_100FULL | BMSR_ANEGCAPABLE) | |
15508 | + | |
15509 | +static bool loopback; | |
15510 | +static bool mii_mode; | |
15511 | +static char *devid; | |
15512 | + | |
15513 | +static struct usb_eth_dev usb_dev_id[] = { | |
15514 | +#define PEGASUS_DEV(pn, vid, pid, flags) \ | |
15515 | + {.name = pn, .vendor = vid, .device = pid, .private = flags}, | |
15516 | +#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \ | |
15517 | + PEGASUS_DEV(pn, vid, pid, flags) | |
15518 | +#include "pegasus.h" | |
15519 | +#undef PEGASUS_DEV | |
15520 | +#undef PEGASUS_DEV_CLASS | |
15521 | + {NULL, 0, 0, 0}, | |
15522 | + {NULL, 0, 0, 0} | |
15523 | +}; | |
15524 | + | |
15525 | +static struct usb_device_id pegasus_ids[] = { | |
15526 | +#define PEGASUS_DEV(pn, vid, pid, flags) \ | |
15527 | + {.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid}, | |
15528 | +/* | |
15529 | + * The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product | |
15530 | + * IDs as the Belkin F5D5050, so we need to teach the pegasus driver to | |
15531 | + * ignore adaptors belonging to the "Wireless" class 0xE0. For this one | |
15532 | + * case anyway, seeing as the pegasus is for "Wired" adaptors. | |
15533 | + */ | |
15534 | +#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \ | |
15535 | + {.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \ | |
15536 | + .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass}, | |
15537 | +#include "pegasus.h" | |
15538 | +#undef PEGASUS_DEV | |
15539 | +#undef PEGASUS_DEV_CLASS | |
15540 | + {}, | |
15541 | + {} | |
15542 | +}; | |
15543 | + | |
15544 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
15545 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
15546 | +MODULE_LICENSE("GPL"); | |
15547 | +module_param(loopback, bool, 0); | |
15548 | +module_param(mii_mode, bool, 0); | |
15549 | +module_param(devid, charp, 0); | |
15550 | +MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); | |
15551 | +MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); | |
15552 | +MODULE_PARM_DESC(devid, "The format is: 'DEV_name:VendorID:DeviceID:Flags'"); | |
15553 | + | |
15554 | +/* use ethtool to change the level for any given device */ | |
15555 | +static int msg_level = -1; | |
15556 | +module_param(msg_level, int, 0); | |
15557 | +MODULE_PARM_DESC(msg_level, "Override default message level"); | |
15558 | + | |
15559 | +MODULE_DEVICE_TABLE(usb, pegasus_ids); | |
15560 | +static const struct net_device_ops pegasus_netdev_ops; | |
15561 | + | |
15562 | +/*****/ | |
15563 | + | |
15564 | +static void async_ctrl_callback(struct urb *urb) | |
15565 | +{ | |
15566 | + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; | |
15567 | + int status = urb->status; | |
15568 | + | |
15569 | + if (status < 0) | |
15570 | + dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); | |
15571 | + kfree(req); | |
15572 | + usb_free_urb(urb); | |
15573 | +} | |
15574 | + | |
15575 | +static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) | |
15576 | +{ | |
15577 | + int ret; | |
15578 | + | |
15579 | + ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), | |
15580 | + PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, | |
15581 | + indx, data, size, 1000); | |
15582 | + if (ret < 0) | |
15583 | + netif_dbg(pegasus, drv, pegasus->net, | |
15584 | + "%s returned %d\n", __func__, ret); | |
15585 | + return ret; | |
15586 | +} | |
15587 | + | |
15588 | +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) | |
15589 | +{ | |
15590 | + int ret; | |
15591 | + | |
15592 | + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), | |
15593 | + PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, | |
15594 | + indx, data, size, 100); | |
15595 | + if (ret < 0) | |
15596 | + netif_dbg(pegasus, drv, pegasus->net, | |
15597 | + "%s returned %d\n", __func__, ret); | |
15598 | + return ret; | |
15599 | +} | |
15600 | + | |
15601 | +static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data) | |
15602 | +{ | |
15603 | + int ret; | |
15604 | + | |
15605 | + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), | |
15606 | + PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, | |
15607 | + indx, &data, 1, 1000); | |
15608 | + if (ret < 0) | |
15609 | + netif_dbg(pegasus, drv, pegasus->net, | |
15610 | + "%s returned %d\n", __func__, ret); | |
15611 | + return ret; | |
15612 | +} | |
15613 | + | |
15614 | +static int update_eth_regs_async(pegasus_t *pegasus) | |
15615 | +{ | |
15616 | + int ret = -ENOMEM; | |
15617 | + struct urb *async_urb; | |
15618 | + struct usb_ctrlrequest *req; | |
15619 | + | |
15620 | + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); | |
15621 | + if (req == NULL) | |
15622 | + return ret; | |
15623 | + | |
15624 | + async_urb = usb_alloc_urb(0, GFP_ATOMIC); | |
15625 | + if (async_urb == NULL) { | |
15626 | + kfree(req); | |
15627 | + return ret; | |
15628 | + } | |
15629 | + req->bRequestType = PEGASUS_REQT_WRITE; | |
15630 | + req->bRequest = PEGASUS_REQ_SET_REGS; | |
15631 | + req->wValue = cpu_to_le16(0); | |
15632 | + req->wIndex = cpu_to_le16(EthCtrl0); | |
15633 | + req->wLength = cpu_to_le16(3); | |
15634 | + | |
15635 | + usb_fill_control_urb(async_urb, pegasus->usb, | |
15636 | + usb_sndctrlpipe(pegasus->usb, 0), (void *)req, | |
15637 | + pegasus->eth_regs, 3, async_ctrl_callback, req); | |
15638 | + | |
15639 | + ret = usb_submit_urb(async_urb, GFP_ATOMIC); | |
15640 | + if (ret) { | |
15641 | + if (ret == -ENODEV) | |
15642 | + netif_device_detach(pegasus->net); | |
15643 | + netif_err(pegasus, drv, pegasus->net, | |
15644 | + "%s returned %d\n", __func__, ret); | |
15645 | + } | |
15646 | + return ret; | |
15647 | +} | |
15648 | + | |
15649 | +static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd) | |
15650 | +{ | |
15651 | + int i; | |
15652 | + __u8 data[4] = { phy, 0, 0, indx }; | |
15653 | + __le16 regdi; | |
15654 | + int ret = -ETIMEDOUT; | |
15655 | + | |
15656 | + if (cmd & PHY_WRITE) { | |
15657 | + __le16 *t = (__le16 *) & data[1]; | |
15658 | + *t = cpu_to_le16(*regd); | |
15659 | + } | |
15660 | + set_register(p, PhyCtrl, 0); | |
15661 | + set_registers(p, PhyAddr, sizeof(data), data); | |
15662 | + set_register(p, PhyCtrl, (indx | cmd)); | |
15663 | + for (i = 0; i < REG_TIMEOUT; i++) { | |
15664 | + ret = get_registers(p, PhyCtrl, 1, data); | |
15665 | + if (ret < 0) | |
15666 | + goto fail; | |
15667 | + if (data[0] & PHY_DONE) | |
15668 | + break; | |
15669 | + } | |
15670 | + if (i >= REG_TIMEOUT) | |
15671 | + goto fail; | |
15672 | + if (cmd & PHY_READ) { | |
15673 | + ret = get_registers(p, PhyData, 2, ®di); | |
15674 | + *regd = le16_to_cpu(regdi); | |
15675 | + return ret; | |
15676 | + } | |
15677 | + return 0; | |
15678 | +fail: | |
15679 | + netif_dbg(p, drv, p->net, "%s failed\n", __func__); | |
15680 | + return ret; | |
15681 | +} | |
15682 | + | |
15683 | +/* Returns non-negative int on success, error on failure */ | |
15684 | +static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) | |
15685 | +{ | |
15686 | + return __mii_op(pegasus, phy, indx, regd, PHY_READ); | |
15687 | +} | |
15688 | + | |
15689 | +/* Returns zero on success, error on failure */ | |
15690 | +static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd) | |
15691 | +{ | |
15692 | + return __mii_op(pegasus, phy, indx, regd, PHY_WRITE); | |
15693 | +} | |
15694 | + | |
15695 | +static int mdio_read(struct net_device *dev, int phy_id, int loc) | |
15696 | +{ | |
15697 | + pegasus_t *pegasus = netdev_priv(dev); | |
15698 | + u16 res; | |
15699 | + | |
15700 | + read_mii_word(pegasus, phy_id, loc, &res); | |
15701 | + return (int)res; | |
15702 | +} | |
15703 | + | |
15704 | +static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) | |
15705 | +{ | |
15706 | + pegasus_t *pegasus = netdev_priv(dev); | |
15707 | + u16 data = val; | |
15708 | + | |
15709 | + write_mii_word(pegasus, phy_id, loc, &data); | |
15710 | +} | |
15711 | + | |
15712 | +static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata) | |
15713 | +{ | |
15714 | + int i; | |
15715 | + __u8 tmp; | |
15716 | + __le16 retdatai; | |
15717 | + int ret; | |
15718 | + | |
15719 | + set_register(pegasus, EpromCtrl, 0); | |
15720 | + set_register(pegasus, EpromOffset, index); | |
15721 | + set_register(pegasus, EpromCtrl, EPROM_READ); | |
15722 | + | |
15723 | + for (i = 0; i < REG_TIMEOUT; i++) { | |
15724 | + ret = get_registers(pegasus, EpromCtrl, 1, &tmp); | |
15725 | + if (tmp & EPROM_DONE) | |
15726 | + break; | |
15727 | + if (ret == -ESHUTDOWN) | |
15728 | + goto fail; | |
15729 | + } | |
15730 | + if (i >= REG_TIMEOUT) | |
15731 | + goto fail; | |
15732 | + | |
15733 | + ret = get_registers(pegasus, EpromData, 2, &retdatai); | |
15734 | + *retdata = le16_to_cpu(retdatai); | |
15735 | + return ret; | |
15736 | + | |
15737 | +fail: | |
15738 | + netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); | |
15739 | + return -ETIMEDOUT; | |
15740 | +} | |
15741 | + | |
15742 | +#ifdef PEGASUS_WRITE_EEPROM | |
15743 | +static inline void enable_eprom_write(pegasus_t *pegasus) | |
15744 | +{ | |
15745 | + __u8 tmp; | |
15746 | + | |
15747 | + get_registers(pegasus, EthCtrl2, 1, &tmp); | |
15748 | + set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE); | |
15749 | +} | |
15750 | + | |
15751 | +static inline void disable_eprom_write(pegasus_t *pegasus) | |
15752 | +{ | |
15753 | + __u8 tmp; | |
15754 | + | |
15755 | + get_registers(pegasus, EthCtrl2, 1, &tmp); | |
15756 | + set_register(pegasus, EpromCtrl, 0); | |
15757 | + set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE); | |
15758 | +} | |
15759 | + | |
15760 | +static int write_eprom_word(pegasus_t *pegasus, __u8 index, __u16 data) | |
15761 | +{ | |
15762 | + int i; | |
15763 | + __u8 tmp, d[4] = { 0x3f, 0, 0, EPROM_WRITE }; | |
15764 | + int ret; | |
15765 | + __le16 le_data = cpu_to_le16(data); | |
15766 | + | |
15767 | + set_registers(pegasus, EpromOffset, 4, d); | |
15768 | + enable_eprom_write(pegasus); | |
15769 | + set_register(pegasus, EpromOffset, index); | |
15770 | + set_registers(pegasus, EpromData, 2, &le_data); | |
15771 | + set_register(pegasus, EpromCtrl, EPROM_WRITE); | |
15772 | + | |
15773 | + for (i = 0; i < REG_TIMEOUT; i++) { | |
15774 | + ret = get_registers(pegasus, EpromCtrl, 1, &tmp); | |
15775 | + if (ret == -ESHUTDOWN) | |
15776 | + goto fail; | |
15777 | + if (tmp & EPROM_DONE) | |
15778 | + break; | |
15779 | + } | |
15780 | + disable_eprom_write(pegasus); | |
15781 | + if (i >= REG_TIMEOUT) | |
15782 | + goto fail; | |
15783 | + | |
15784 | + return ret; | |
15785 | + | |
15786 | +fail: | |
15787 | + netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__); | |
15788 | + return -ETIMEDOUT; | |
15789 | +} | |
15790 | +#endif /* PEGASUS_WRITE_EEPROM */ | |
15791 | + | |
15792 | +static inline void get_node_id(pegasus_t *pegasus, __u8 *id) | |
15793 | +{ | |
15794 | + int i; | |
15795 | + __u16 w16; | |
15796 | + | |
15797 | + for (i = 0; i < 3; i++) { | |
15798 | + read_eprom_word(pegasus, i, &w16); | |
15799 | + ((__le16 *) id)[i] = cpu_to_le16(w16); | |
15800 | + } | |
15801 | +} | |
15802 | + | |
15803 | +static void set_ethernet_addr(pegasus_t *pegasus) | |
15804 | +{ | |
15805 | + __u8 node_id[6]; | |
15806 | + | |
15807 | + if (pegasus->features & PEGASUS_II) { | |
15808 | + get_registers(pegasus, 0x10, sizeof(node_id), node_id); | |
15809 | + } else { | |
15810 | + get_node_id(pegasus, node_id); | |
15811 | + set_registers(pegasus, EthID, sizeof(node_id), node_id); | |
15812 | + } | |
15813 | + memcpy(pegasus->net->dev_addr, node_id, sizeof(node_id)); | |
15814 | +} | |
15815 | + | |
15816 | +static inline int reset_mac(pegasus_t *pegasus) | |
15817 | +{ | |
15818 | + __u8 data = 0x8; | |
15819 | + int i; | |
15820 | + | |
15821 | + set_register(pegasus, EthCtrl1, data); | |
15822 | + for (i = 0; i < REG_TIMEOUT; i++) { | |
15823 | + get_registers(pegasus, EthCtrl1, 1, &data); | |
15824 | + if (~data & 0x08) { | |
15825 | + if (loopback) | |
15826 | + break; | |
15827 | + if (mii_mode && (pegasus->features & HAS_HOME_PNA)) | |
15828 | + set_register(pegasus, Gpio1, 0x34); | |
15829 | + else | |
15830 | + set_register(pegasus, Gpio1, 0x26); | |
15831 | + set_register(pegasus, Gpio0, pegasus->features); | |
15832 | + set_register(pegasus, Gpio0, DEFAULT_GPIO_SET); | |
15833 | + break; | |
15834 | + } | |
15835 | + } | |
15836 | + if (i == REG_TIMEOUT) | |
15837 | + return -ETIMEDOUT; | |
15838 | + | |
15839 | + if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || | |
15840 | + usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { | |
15841 | + set_register(pegasus, Gpio0, 0x24); | |
15842 | + set_register(pegasus, Gpio0, 0x26); | |
15843 | + } | |
15844 | + if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) { | |
15845 | + __u16 auxmode; | |
15846 | + read_mii_word(pegasus, 3, 0x1b, &auxmode); | |
15847 | + auxmode |= 4; | |
15848 | + write_mii_word(pegasus, 3, 0x1b, &auxmode); | |
15849 | + } | |
15850 | + | |
15851 | + return 0; | |
15852 | +} | |
15853 | + | |
15854 | +static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) | |
15855 | +{ | |
15856 | + __u16 linkpart; | |
15857 | + __u8 data[4]; | |
15858 | + pegasus_t *pegasus = netdev_priv(dev); | |
15859 | + int ret; | |
15860 | + | |
15861 | + read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart); | |
15862 | + data[0] = 0xc9; | |
15863 | + data[1] = 0; | |
15864 | + if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL)) | |
15865 | + data[1] |= 0x20; /* set full duplex */ | |
15866 | + if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF)) | |
15867 | + data[1] |= 0x10; /* set 100 Mbps */ | |
15868 | + if (mii_mode) | |
15869 | + data[1] = 0; | |
15870 | + data[2] = loopback ? 0x09 : 0x01; | |
15871 | + | |
15872 | + memcpy(pegasus->eth_regs, data, sizeof(data)); | |
15873 | + ret = set_registers(pegasus, EthCtrl0, 3, data); | |
15874 | + | |
15875 | + if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS || | |
15876 | + usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 || | |
15877 | + usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) { | |
15878 | + u16 auxmode; | |
15879 | + read_mii_word(pegasus, 0, 0x1b, &auxmode); | |
15880 | + auxmode |= 4; | |
15881 | + write_mii_word(pegasus, 0, 0x1b, &auxmode); | |
15882 | + } | |
15883 | + | |
15884 | + return ret; | |
15885 | +} | |
15886 | + | |
15887 | +static void read_bulk_callback(struct urb *urb) | |
15888 | +{ | |
15889 | + pegasus_t *pegasus = urb->context; | |
15890 | + struct net_device *net; | |
15891 | + int rx_status, count = urb->actual_length; | |
15892 | + int status = urb->status; | |
15893 | + u8 *buf = urb->transfer_buffer; | |
15894 | + __u16 pkt_len; | |
15895 | + | |
15896 | + if (!pegasus) | |
15897 | + return; | |
15898 | + | |
15899 | + net = pegasus->net; | |
15900 | + if (!netif_device_present(net) || !netif_running(net)) | |
15901 | + return; | |
15902 | + | |
15903 | + switch (status) { | |
15904 | + case 0: | |
15905 | + break; | |
15906 | + case -ETIME: | |
15907 | + netif_dbg(pegasus, rx_err, net, "reset MAC\n"); | |
15908 | + pegasus->flags &= ~PEGASUS_RX_BUSY; | |
15909 | + break; | |
15910 | + case -EPIPE: /* stall, or disconnect from TT */ | |
15911 | + /* FIXME schedule work to clear the halt */ | |
15912 | + netif_warn(pegasus, rx_err, net, "no rx stall recovery\n"); | |
15913 | + return; | |
15914 | + case -ENOENT: | |
15915 | + case -ECONNRESET: | |
15916 | + case -ESHUTDOWN: | |
15917 | + netif_dbg(pegasus, ifdown, net, "rx unlink, %d\n", status); | |
15918 | + return; | |
15919 | + default: | |
15920 | + netif_dbg(pegasus, rx_err, net, "RX status %d\n", status); | |
15921 | + goto goon; | |
15922 | + } | |
15923 | + | |
15924 | + if (!count || count < 4) | |
15925 | + goto goon; | |
15926 | + | |
15927 | + rx_status = buf[count - 2]; | |
15928 | + if (rx_status & 0x1e) { | |
15929 | + netif_dbg(pegasus, rx_err, net, | |
15930 | + "RX packet error %x\n", rx_status); | |
15931 | + pegasus->stats.rx_errors++; | |
15932 | + if (rx_status & 0x06) /* long or runt */ | |
15933 | + pegasus->stats.rx_length_errors++; | |
15934 | + if (rx_status & 0x08) | |
15935 | + pegasus->stats.rx_crc_errors++; | |
15936 | + if (rx_status & 0x10) /* extra bits */ | |
15937 | + pegasus->stats.rx_frame_errors++; | |
15938 | + goto goon; | |
15939 | + } | |
15940 | + if (pegasus->chip == 0x8513) { | |
15941 | + pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer); | |
15942 | + pkt_len &= 0x0fff; | |
15943 | + pegasus->rx_skb->data += 2; | |
15944 | + } else { | |
15945 | + pkt_len = buf[count - 3] << 8; | |
15946 | + pkt_len += buf[count - 4]; | |
15947 | + pkt_len &= 0xfff; | |
15948 | + pkt_len -= 8; | |
15949 | + } | |
15950 | + | |
15951 | + /* | |
15952 | + * If the packet is unreasonably long, quietly drop it rather than | |
15953 | + * kernel panicing by calling skb_put. | |
15954 | + */ | |
15955 | + if (pkt_len > PEGASUS_MTU) | |
15956 | + goto goon; | |
15957 | + | |
15958 | + /* | |
15959 | + * at this point we are sure pegasus->rx_skb != NULL | |
15960 | + * so we go ahead and pass up the packet. | |
15961 | + */ | |
15962 | + skb_put(pegasus->rx_skb, pkt_len); | |
15963 | + pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net); | |
15964 | + netif_rx(pegasus->rx_skb); | |
15965 | + pegasus->stats.rx_packets++; | |
15966 | + pegasus->stats.rx_bytes += pkt_len; | |
15967 | + | |
15968 | + if (pegasus->flags & PEGASUS_UNPLUG) | |
15969 | + return; | |
15970 | + | |
15971 | + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU, | |
15972 | + GFP_ATOMIC); | |
15973 | + | |
15974 | + if (pegasus->rx_skb == NULL) | |
15975 | + goto tl_sched; | |
15976 | +goon: | |
15977 | + usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | |
15978 | + usb_rcvbulkpipe(pegasus->usb, 1), | |
15979 | + pegasus->rx_skb->data, PEGASUS_MTU + 8, | |
15980 | + read_bulk_callback, pegasus); | |
15981 | + rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); | |
15982 | + if (rx_status == -ENODEV) | |
15983 | + netif_device_detach(pegasus->net); | |
15984 | + else if (rx_status) { | |
15985 | + pegasus->flags |= PEGASUS_RX_URB_FAIL; | |
15986 | + goto tl_sched; | |
15987 | + } else { | |
15988 | + pegasus->flags &= ~PEGASUS_RX_URB_FAIL; | |
15989 | + } | |
15990 | + | |
15991 | + return; | |
15992 | + | |
15993 | +tl_sched: | |
15994 | + tasklet_schedule(&pegasus->rx_tl); | |
15995 | +} | |
15996 | + | |
15997 | +static void rx_fixup(unsigned long data) | |
15998 | +{ | |
15999 | + pegasus_t *pegasus; | |
16000 | + int status; | |
16001 | + | |
16002 | + pegasus = (pegasus_t *) data; | |
16003 | + if (pegasus->flags & PEGASUS_UNPLUG) | |
16004 | + return; | |
16005 | + | |
16006 | + if (pegasus->flags & PEGASUS_RX_URB_FAIL) | |
16007 | + if (pegasus->rx_skb) | |
16008 | + goto try_again; | |
16009 | + if (pegasus->rx_skb == NULL) | |
16010 | + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, | |
16011 | + PEGASUS_MTU, | |
16012 | + GFP_ATOMIC); | |
16013 | + if (pegasus->rx_skb == NULL) { | |
16014 | + netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n"); | |
16015 | + tasklet_schedule(&pegasus->rx_tl); | |
16016 | + return; | |
16017 | + } | |
16018 | + usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | |
16019 | + usb_rcvbulkpipe(pegasus->usb, 1), | |
16020 | + pegasus->rx_skb->data, PEGASUS_MTU + 8, | |
16021 | + read_bulk_callback, pegasus); | |
16022 | +try_again: | |
16023 | + status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); | |
16024 | + if (status == -ENODEV) | |
16025 | + netif_device_detach(pegasus->net); | |
16026 | + else if (status) { | |
16027 | + pegasus->flags |= PEGASUS_RX_URB_FAIL; | |
16028 | + tasklet_schedule(&pegasus->rx_tl); | |
16029 | + } else { | |
16030 | + pegasus->flags &= ~PEGASUS_RX_URB_FAIL; | |
16031 | + } | |
16032 | +} | |
16033 | + | |
16034 | +static void write_bulk_callback(struct urb *urb) | |
16035 | +{ | |
16036 | + pegasus_t *pegasus = urb->context; | |
16037 | + struct net_device *net; | |
16038 | + int status = urb->status; | |
16039 | + | |
16040 | + if (!pegasus) | |
16041 | + return; | |
16042 | + | |
16043 | + net = pegasus->net; | |
16044 | + | |
16045 | + if (!netif_device_present(net) || !netif_running(net)) | |
16046 | + return; | |
16047 | + | |
16048 | + switch (status) { | |
16049 | + case -EPIPE: | |
16050 | + /* FIXME schedule_work() to clear the tx halt */ | |
16051 | + netif_stop_queue(net); | |
16052 | + netif_warn(pegasus, tx_err, net, "no tx stall recovery\n"); | |
16053 | + return; | |
16054 | + case -ENOENT: | |
16055 | + case -ECONNRESET: | |
16056 | + case -ESHUTDOWN: | |
16057 | + netif_dbg(pegasus, ifdown, net, "tx unlink, %d\n", status); | |
16058 | + return; | |
16059 | + default: | |
16060 | + netif_info(pegasus, tx_err, net, "TX status %d\n", status); | |
16061 | + /* FALL THROUGH */ | |
16062 | + case 0: | |
16063 | + break; | |
16064 | + } | |
16065 | + | |
16066 | + net->trans_start = jiffies; /* prevent tx timeout */ | |
16067 | + netif_wake_queue(net); | |
16068 | +} | |
16069 | + | |
16070 | +static void intr_callback(struct urb *urb) | |
16071 | +{ | |
16072 | + pegasus_t *pegasus = urb->context; | |
16073 | + struct net_device *net; | |
16074 | + int res, status = urb->status; | |
16075 | + | |
16076 | + if (!pegasus) | |
16077 | + return; | |
16078 | + net = pegasus->net; | |
16079 | + | |
16080 | + switch (status) { | |
16081 | + case 0: | |
16082 | + break; | |
16083 | + case -ECONNRESET: /* unlink */ | |
16084 | + case -ENOENT: | |
16085 | + case -ESHUTDOWN: | |
16086 | + return; | |
16087 | + default: | |
16088 | + /* some Pegasus-I products report LOTS of data | |
16089 | + * toggle errors... avoid log spamming | |
16090 | + */ | |
16091 | + netif_dbg(pegasus, timer, net, "intr status %d\n", status); | |
16092 | + } | |
16093 | + | |
16094 | + if (urb->actual_length >= 6) { | |
16095 | + u8 *d = urb->transfer_buffer; | |
16096 | + | |
16097 | + /* byte 0 == tx_status1, reg 2B */ | |
16098 | + if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL | |
16099 | + |LATE_COL|JABBER_TIMEOUT)) { | |
16100 | + pegasus->stats.tx_errors++; | |
16101 | + if (d[0] & TX_UNDERRUN) | |
16102 | + pegasus->stats.tx_fifo_errors++; | |
16103 | + if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) | |
16104 | + pegasus->stats.tx_aborted_errors++; | |
16105 | + if (d[0] & LATE_COL) | |
16106 | + pegasus->stats.tx_window_errors++; | |
16107 | + } | |
16108 | + | |
16109 | + /* d[5].LINK_STATUS lies on some adapters. | |
16110 | + * d[0].NO_CARRIER kicks in only with failed TX. | |
16111 | + * ... so monitoring with MII may be safest. | |
16112 | + */ | |
16113 | + | |
16114 | + /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ | |
16115 | + pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; | |
16116 | + } | |
16117 | + | |
16118 | + res = usb_submit_urb(urb, GFP_ATOMIC); | |
16119 | + if (res == -ENODEV) | |
16120 | + netif_device_detach(pegasus->net); | |
16121 | + if (res) | |
16122 | + netif_err(pegasus, timer, net, | |
16123 | + "can't resubmit interrupt urb, %d\n", res); | |
16124 | +} | |
16125 | + | |
16126 | +static void pegasus_tx_timeout(struct net_device *net) | |
16127 | +{ | |
16128 | + pegasus_t *pegasus = netdev_priv(net); | |
16129 | + netif_warn(pegasus, timer, net, "tx timeout\n"); | |
16130 | + usb_unlink_urb(pegasus->tx_urb); | |
16131 | + pegasus->stats.tx_errors++; | |
16132 | +} | |
16133 | + | |
16134 | +static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb, | |
16135 | + struct net_device *net) | |
16136 | +{ | |
16137 | + pegasus_t *pegasus = netdev_priv(net); | |
16138 | + int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3; | |
16139 | + int res; | |
16140 | + __u16 l16 = skb->len; | |
16141 | + | |
16142 | + netif_stop_queue(net); | |
16143 | + | |
16144 | + ((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16); | |
16145 | + skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len); | |
16146 | + usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb, | |
16147 | + usb_sndbulkpipe(pegasus->usb, 2), | |
16148 | + pegasus->tx_buff, count, | |
16149 | + write_bulk_callback, pegasus); | |
16150 | + if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { | |
16151 | + netif_warn(pegasus, tx_err, net, "fail tx, %d\n", res); | |
16152 | + switch (res) { | |
16153 | + case -EPIPE: /* stall, or disconnect from TT */ | |
16154 | + /* cleanup should already have been scheduled */ | |
16155 | + break; | |
16156 | + case -ENODEV: /* disconnect() upcoming */ | |
16157 | + case -EPERM: | |
16158 | + netif_device_detach(pegasus->net); | |
16159 | + break; | |
16160 | + default: | |
16161 | + pegasus->stats.tx_errors++; | |
16162 | + netif_start_queue(net); | |
16163 | + } | |
16164 | + } else { | |
16165 | + pegasus->stats.tx_packets++; | |
16166 | + pegasus->stats.tx_bytes += skb->len; | |
16167 | + } | |
16168 | + dev_kfree_skb(skb); | |
16169 | + | |
16170 | + return NETDEV_TX_OK; | |
16171 | +} | |
16172 | + | |
16173 | +static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) | |
16174 | +{ | |
16175 | + return &((pegasus_t *) netdev_priv(dev))->stats; | |
16176 | +} | |
16177 | + | |
16178 | +static inline void disable_net_traffic(pegasus_t *pegasus) | |
16179 | +{ | |
16180 | + __le16 tmp = cpu_to_le16(0); | |
16181 | + | |
16182 | + set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); | |
16183 | +} | |
16184 | + | |
16185 | +static inline void get_interrupt_interval(pegasus_t *pegasus) | |
16186 | +{ | |
16187 | + u16 data; | |
16188 | + u8 interval; | |
16189 | + | |
16190 | + read_eprom_word(pegasus, 4, &data); | |
16191 | + interval = data >> 8; | |
16192 | + if (pegasus->usb->speed != USB_SPEED_HIGH) { | |
16193 | + if (interval < 0x80) { | |
16194 | + netif_info(pegasus, timer, pegasus->net, | |
16195 | + "intr interval changed from %ums to %ums\n", | |
16196 | + interval, 0x80); | |
16197 | + interval = 0x80; | |
16198 | + data = (data & 0x00FF) | ((u16)interval << 8); | |
16199 | +#ifdef PEGASUS_WRITE_EEPROM | |
16200 | + write_eprom_word(pegasus, 4, data); | |
16201 | +#endif | |
16202 | + } | |
16203 | + } | |
16204 | + pegasus->intr_interval = interval; | |
16205 | +} | |
16206 | + | |
16207 | +static void set_carrier(struct net_device *net) | |
16208 | +{ | |
16209 | + pegasus_t *pegasus = netdev_priv(net); | |
16210 | + u16 tmp; | |
16211 | + | |
16212 | + if (read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp)) | |
16213 | + return; | |
16214 | + | |
16215 | + if (tmp & BMSR_LSTATUS) | |
16216 | + netif_carrier_on(net); | |
16217 | + else | |
16218 | + netif_carrier_off(net); | |
16219 | +} | |
16220 | + | |
16221 | +static void free_all_urbs(pegasus_t *pegasus) | |
16222 | +{ | |
16223 | + usb_free_urb(pegasus->intr_urb); | |
16224 | + usb_free_urb(pegasus->tx_urb); | |
16225 | + usb_free_urb(pegasus->rx_urb); | |
16226 | +} | |
16227 | + | |
16228 | +static void unlink_all_urbs(pegasus_t *pegasus) | |
16229 | +{ | |
16230 | + usb_kill_urb(pegasus->intr_urb); | |
16231 | + usb_kill_urb(pegasus->tx_urb); | |
16232 | + usb_kill_urb(pegasus->rx_urb); | |
16233 | +} | |
16234 | + | |
16235 | +static int alloc_urbs(pegasus_t *pegasus) | |
16236 | +{ | |
16237 | + int res = -ENOMEM; | |
16238 | + | |
16239 | + pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
16240 | + if (!pegasus->rx_urb) { | |
16241 | + return res; | |
16242 | + } | |
16243 | + pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
16244 | + if (!pegasus->tx_urb) { | |
16245 | + usb_free_urb(pegasus->rx_urb); | |
16246 | + return res; | |
16247 | + } | |
16248 | + pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | |
16249 | + if (!pegasus->intr_urb) { | |
16250 | + usb_free_urb(pegasus->tx_urb); | |
16251 | + usb_free_urb(pegasus->rx_urb); | |
16252 | + return res; | |
16253 | + } | |
16254 | + | |
16255 | + return 0; | |
16256 | +} | |
16257 | + | |
16258 | +static int pegasus_open(struct net_device *net) | |
16259 | +{ | |
16260 | + pegasus_t *pegasus = netdev_priv(net); | |
16261 | + int res=-ENOMEM; | |
16262 | + | |
16263 | + if (pegasus->rx_skb == NULL) | |
16264 | + pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, | |
16265 | + PEGASUS_MTU, | |
16266 | + GFP_KERNEL); | |
16267 | + if (!pegasus->rx_skb) | |
16268 | + goto exit; | |
16269 | + | |
16270 | + res = set_registers(pegasus, EthID, 6, net->dev_addr); | |
16271 | + | |
16272 | + usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, | |
16273 | + usb_rcvbulkpipe(pegasus->usb, 1), | |
16274 | + pegasus->rx_skb->data, PEGASUS_MTU + 8, | |
16275 | + read_bulk_callback, pegasus); | |
16276 | + if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { | |
16277 | + if (res == -ENODEV) | |
16278 | + netif_device_detach(pegasus->net); | |
16279 | + netif_dbg(pegasus, ifup, net, "failed rx_urb, %d\n", res); | |
16280 | + goto exit; | |
16281 | + } | |
16282 | + | |
16283 | + usb_fill_int_urb(pegasus->intr_urb, pegasus->usb, | |
16284 | + usb_rcvintpipe(pegasus->usb, 3), | |
16285 | + pegasus->intr_buff, sizeof(pegasus->intr_buff), | |
16286 | + intr_callback, pegasus, pegasus->intr_interval); | |
16287 | + if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { | |
16288 | + if (res == -ENODEV) | |
16289 | + netif_device_detach(pegasus->net); | |
16290 | + netif_dbg(pegasus, ifup, net, "failed intr_urb, %d\n", res); | |
16291 | + usb_kill_urb(pegasus->rx_urb); | |
16292 | + goto exit; | |
16293 | + } | |
16294 | + res = enable_net_traffic(net, pegasus->usb); | |
16295 | + if (res < 0) { | |
16296 | + netif_dbg(pegasus, ifup, net, | |
16297 | + "can't enable_net_traffic() - %d\n", res); | |
16298 | + res = -EIO; | |
16299 | + usb_kill_urb(pegasus->rx_urb); | |
16300 | + usb_kill_urb(pegasus->intr_urb); | |
16301 | + goto exit; | |
16302 | + } | |
16303 | + set_carrier(net); | |
16304 | + netif_start_queue(net); | |
16305 | + netif_dbg(pegasus, ifup, net, "open\n"); | |
16306 | + res = 0; | |
16307 | +exit: | |
16308 | + return res; | |
16309 | +} | |
16310 | + | |
16311 | +static int pegasus_close(struct net_device *net) | |
16312 | +{ | |
16313 | + pegasus_t *pegasus = netdev_priv(net); | |
16314 | + | |
16315 | + netif_stop_queue(net); | |
16316 | + if (!(pegasus->flags & PEGASUS_UNPLUG)) | |
16317 | + disable_net_traffic(pegasus); | |
16318 | + tasklet_kill(&pegasus->rx_tl); | |
16319 | + unlink_all_urbs(pegasus); | |
16320 | + | |
16321 | + return 0; | |
16322 | +} | |
16323 | + | |
16324 | +static void pegasus_get_drvinfo(struct net_device *dev, | |
16325 | + struct ethtool_drvinfo *info) | |
16326 | +{ | |
16327 | + pegasus_t *pegasus = netdev_priv(dev); | |
16328 | + | |
16329 | + strlcpy(info->driver, driver_name, sizeof(info->driver)); | |
16330 | + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
16331 | + usb_make_path(pegasus->usb, info->bus_info, sizeof(info->bus_info)); | |
16332 | +} | |
16333 | + | |
16334 | +/* also handles three patterns of some kind in hardware */ | |
16335 | +#define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) | |
16336 | + | |
16337 | +static void | |
16338 | +pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
16339 | +{ | |
16340 | + pegasus_t *pegasus = netdev_priv(dev); | |
16341 | + | |
16342 | + wol->supported = WAKE_MAGIC | WAKE_PHY; | |
16343 | + wol->wolopts = pegasus->wolopts; | |
16344 | +} | |
16345 | + | |
16346 | +static int | |
16347 | +pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
16348 | +{ | |
16349 | + pegasus_t *pegasus = netdev_priv(dev); | |
16350 | + u8 reg78 = 0x04; | |
16351 | + int ret; | |
16352 | + | |
16353 | + if (wol->wolopts & ~WOL_SUPPORTED) | |
16354 | + return -EINVAL; | |
16355 | + | |
16356 | + if (wol->wolopts & WAKE_MAGIC) | |
16357 | + reg78 |= 0x80; | |
16358 | + if (wol->wolopts & WAKE_PHY) | |
16359 | + reg78 |= 0x40; | |
16360 | + /* FIXME this 0x10 bit still needs to get set in the chip... */ | |
16361 | + if (wol->wolopts) | |
16362 | + pegasus->eth_regs[0] |= 0x10; | |
16363 | + else | |
16364 | + pegasus->eth_regs[0] &= ~0x10; | |
16365 | + pegasus->wolopts = wol->wolopts; | |
16366 | + | |
16367 | + ret = set_register(pegasus, WakeupControl, reg78); | |
16368 | + if (!ret) | |
16369 | + ret = device_set_wakeup_enable(&pegasus->usb->dev, | |
16370 | + wol->wolopts); | |
16371 | + return ret; | |
16372 | +} | |
16373 | + | |
16374 | +static inline void pegasus_reset_wol(struct net_device *dev) | |
16375 | +{ | |
16376 | + struct ethtool_wolinfo wol; | |
16377 | + | |
16378 | + memset(&wol, 0, sizeof wol); | |
16379 | + (void) pegasus_set_wol(dev, &wol); | |
16380 | +} | |
16381 | + | |
16382 | +static int | |
16383 | +pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |
16384 | +{ | |
16385 | + pegasus_t *pegasus; | |
16386 | + | |
16387 | + pegasus = netdev_priv(dev); | |
16388 | + mii_ethtool_gset(&pegasus->mii, ecmd); | |
16389 | + return 0; | |
16390 | +} | |
16391 | + | |
16392 | +static int | |
16393 | +pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |
16394 | +{ | |
16395 | + pegasus_t *pegasus = netdev_priv(dev); | |
16396 | + return mii_ethtool_sset(&pegasus->mii, ecmd); | |
16397 | +} | |
16398 | + | |
16399 | +static int pegasus_nway_reset(struct net_device *dev) | |
16400 | +{ | |
16401 | + pegasus_t *pegasus = netdev_priv(dev); | |
16402 | + return mii_nway_restart(&pegasus->mii); | |
16403 | +} | |
16404 | + | |
16405 | +static u32 pegasus_get_link(struct net_device *dev) | |
16406 | +{ | |
16407 | + pegasus_t *pegasus = netdev_priv(dev); | |
16408 | + return mii_link_ok(&pegasus->mii); | |
16409 | +} | |
16410 | + | |
16411 | +static u32 pegasus_get_msglevel(struct net_device *dev) | |
16412 | +{ | |
16413 | + pegasus_t *pegasus = netdev_priv(dev); | |
16414 | + return pegasus->msg_enable; | |
16415 | +} | |
16416 | + | |
16417 | +static void pegasus_set_msglevel(struct net_device *dev, u32 v) | |
16418 | +{ | |
16419 | + pegasus_t *pegasus = netdev_priv(dev); | |
16420 | + pegasus->msg_enable = v; | |
16421 | +} | |
16422 | + | |
16423 | +static const struct ethtool_ops ops = { | |
16424 | + .get_drvinfo = pegasus_get_drvinfo, | |
16425 | + .get_settings = pegasus_get_settings, | |
16426 | + .set_settings = pegasus_set_settings, | |
16427 | + .nway_reset = pegasus_nway_reset, | |
16428 | + .get_link = pegasus_get_link, | |
16429 | + .get_msglevel = pegasus_get_msglevel, | |
16430 | + .set_msglevel = pegasus_set_msglevel, | |
16431 | + .get_wol = pegasus_get_wol, | |
16432 | + .set_wol = pegasus_set_wol, | |
16433 | +}; | |
16434 | + | |
16435 | +static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
16436 | +{ | |
16437 | + __u16 *data = (__u16 *) &rq->ifr_ifru; | |
16438 | + pegasus_t *pegasus = netdev_priv(net); | |
16439 | + int res; | |
16440 | + | |
16441 | + switch (cmd) { | |
16442 | + case SIOCDEVPRIVATE: | |
16443 | + data[0] = pegasus->phy; | |
16444 | + case SIOCDEVPRIVATE + 1: | |
16445 | + read_mii_word(pegasus, data[0], data[1] & 0x1f, &data[3]); | |
16446 | + res = 0; | |
16447 | + break; | |
16448 | + case SIOCDEVPRIVATE + 2: | |
16449 | + if (!capable(CAP_NET_ADMIN)) | |
16450 | + return -EPERM; | |
16451 | + write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]); | |
16452 | + res = 0; | |
16453 | + break; | |
16454 | + default: | |
16455 | + res = -EOPNOTSUPP; | |
16456 | + } | |
16457 | + return res; | |
16458 | +} | |
16459 | + | |
16460 | +static void pegasus_set_multicast(struct net_device *net) | |
16461 | +{ | |
16462 | + pegasus_t *pegasus = netdev_priv(net); | |
16463 | + | |
16464 | + if (net->flags & IFF_PROMISC) { | |
16465 | + pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; | |
16466 | + netif_info(pegasus, link, net, "Promiscuous mode enabled\n"); | |
16467 | + } else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { | |
16468 | + pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; | |
16469 | + pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | |
16470 | + netif_dbg(pegasus, link, net, "set allmulti\n"); | |
16471 | + } else { | |
16472 | + pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; | |
16473 | + pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | |
16474 | + } | |
16475 | + update_eth_regs_async(pegasus); | |
16476 | +} | |
16477 | + | |
16478 | +static __u8 mii_phy_probe(pegasus_t *pegasus) | |
16479 | +{ | |
16480 | + int i; | |
16481 | + __u16 tmp; | |
16482 | + | |
16483 | + for (i = 0; i < 32; i++) { | |
16484 | + read_mii_word(pegasus, i, MII_BMSR, &tmp); | |
16485 | + if (tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0) | |
16486 | + continue; | |
16487 | + else | |
16488 | + return i; | |
16489 | + } | |
16490 | + | |
16491 | + return 0xff; | |
16492 | +} | |
16493 | + | |
16494 | +static inline void setup_pegasus_II(pegasus_t *pegasus) | |
16495 | +{ | |
16496 | + __u8 data = 0xa5; | |
16497 | + | |
16498 | + set_register(pegasus, Reg1d, 0); | |
16499 | + set_register(pegasus, Reg7b, 1); | |
16500 | + mdelay(100); | |
16501 | + if ((pegasus->features & HAS_HOME_PNA) && mii_mode) | |
16502 | + set_register(pegasus, Reg7b, 0); | |
16503 | + else | |
16504 | + set_register(pegasus, Reg7b, 2); | |
16505 | + | |
16506 | + set_register(pegasus, 0x83, data); | |
16507 | + get_registers(pegasus, 0x83, 1, &data); | |
16508 | + | |
16509 | + if (data == 0xa5) | |
16510 | + pegasus->chip = 0x8513; | |
16511 | + else | |
16512 | + pegasus->chip = 0; | |
16513 | + | |
16514 | + set_register(pegasus, 0x80, 0xc0); | |
16515 | + set_register(pegasus, 0x83, 0xff); | |
16516 | + set_register(pegasus, 0x84, 0x01); | |
16517 | + | |
16518 | + if (pegasus->features & HAS_HOME_PNA && mii_mode) | |
16519 | + set_register(pegasus, Reg81, 6); | |
16520 | + else | |
16521 | + set_register(pegasus, Reg81, 2); | |
16522 | +} | |
16523 | + | |
16524 | + | |
16525 | +static int pegasus_count; | |
16526 | +static struct workqueue_struct *pegasus_workqueue; | |
16527 | +#define CARRIER_CHECK_DELAY (2 * HZ) | |
16528 | + | |
16529 | +static void check_carrier(struct work_struct *work) | |
16530 | +{ | |
16531 | + pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); | |
16532 | + set_carrier(pegasus->net); | |
16533 | + if (!(pegasus->flags & PEGASUS_UNPLUG)) { | |
16534 | + queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | |
16535 | + CARRIER_CHECK_DELAY); | |
16536 | + } | |
16537 | +} | |
16538 | + | |
16539 | +static int pegasus_blacklisted(struct usb_device *udev) | |
16540 | +{ | |
16541 | + struct usb_device_descriptor *udd = &udev->descriptor; | |
16542 | + | |
16543 | + /* Special quirk to keep the driver from handling the Belkin Bluetooth | |
16544 | + * dongle which happens to have the same ID. | |
16545 | + */ | |
16546 | + if ((udd->idVendor == cpu_to_le16(VENDOR_BELKIN)) && | |
16547 | + (udd->idProduct == cpu_to_le16(0x0121)) && | |
16548 | + (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) && | |
16549 | + (udd->bDeviceProtocol == 1)) | |
16550 | + return 1; | |
16551 | + | |
16552 | + return 0; | |
16553 | +} | |
16554 | + | |
16555 | +/* we rely on probe() and remove() being serialized so we | |
16556 | + * don't need extra locking on pegasus_count. | |
16557 | + */ | |
16558 | +static void pegasus_dec_workqueue(void) | |
16559 | +{ | |
16560 | + pegasus_count--; | |
16561 | + if (pegasus_count == 0) { | |
16562 | + destroy_workqueue(pegasus_workqueue); | |
16563 | + pegasus_workqueue = NULL; | |
16564 | + } | |
16565 | +} | |
16566 | + | |
16567 | +static int pegasus_probe(struct usb_interface *intf, | |
16568 | + const struct usb_device_id *id) | |
16569 | +{ | |
16570 | + struct usb_device *dev = interface_to_usbdev(intf); | |
16571 | + struct net_device *net; | |
16572 | + pegasus_t *pegasus; | |
16573 | + int dev_index = id - pegasus_ids; | |
16574 | + int res = -ENOMEM; | |
16575 | + | |
16576 | + if (pegasus_blacklisted(dev)) | |
16577 | + return -ENODEV; | |
16578 | + | |
16579 | + if (pegasus_count == 0) { | |
16580 | + pegasus_workqueue = create_singlethread_workqueue("pegasus"); | |
16581 | + if (!pegasus_workqueue) | |
16582 | + return -ENOMEM; | |
16583 | + } | |
16584 | + pegasus_count++; | |
16585 | + | |
16586 | + net = alloc_etherdev(sizeof(struct pegasus)); | |
16587 | + if (!net) | |
16588 | + goto out; | |
16589 | + | |
16590 | + pegasus = netdev_priv(net); | |
16591 | + pegasus->dev_index = dev_index; | |
16592 | + | |
16593 | + res = alloc_urbs(pegasus); | |
16594 | + if (res < 0) { | |
16595 | + dev_err(&intf->dev, "can't allocate %s\n", "urbs"); | |
16596 | + goto out1; | |
16597 | + } | |
16598 | + | |
16599 | + tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); | |
16600 | + | |
16601 | + INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); | |
16602 | + | |
16603 | + pegasus->intf = intf; | |
16604 | + pegasus->usb = dev; | |
16605 | + pegasus->net = net; | |
16606 | + | |
16607 | + | |
16608 | + net->watchdog_timeo = PEGASUS_TX_TIMEOUT; | |
16609 | + net->netdev_ops = &pegasus_netdev_ops; | |
16610 | + net->ethtool_ops = &ops; | |
16611 | + pegasus->mii.dev = net; | |
16612 | + pegasus->mii.mdio_read = mdio_read; | |
16613 | + pegasus->mii.mdio_write = mdio_write; | |
16614 | + pegasus->mii.phy_id_mask = 0x1f; | |
16615 | + pegasus->mii.reg_num_mask = 0x1f; | |
16616 | + pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | |
16617 | + | NETIF_MSG_PROBE | NETIF_MSG_LINK); | |
16618 | + | |
16619 | + pegasus->features = usb_dev_id[dev_index].private; | |
16620 | + get_interrupt_interval(pegasus); | |
16621 | + if (reset_mac(pegasus)) { | |
16622 | + dev_err(&intf->dev, "can't reset MAC\n"); | |
16623 | + res = -EIO; | |
16624 | + goto out2; | |
16625 | + } | |
16626 | + set_ethernet_addr(pegasus); | |
16627 | + if (pegasus->features & PEGASUS_II) { | |
16628 | + dev_info(&intf->dev, "setup Pegasus II specific registers\n"); | |
16629 | + setup_pegasus_II(pegasus); | |
16630 | + } | |
16631 | + pegasus->phy = mii_phy_probe(pegasus); | |
16632 | + if (pegasus->phy == 0xff) { | |
16633 | + dev_warn(&intf->dev, "can't locate MII phy, using default\n"); | |
16634 | + pegasus->phy = 1; | |
16635 | + } | |
16636 | + pegasus->mii.phy_id = pegasus->phy; | |
16637 | + usb_set_intfdata(intf, pegasus); | |
16638 | + SET_NETDEV_DEV(net, &intf->dev); | |
16639 | + pegasus_reset_wol(net); | |
16640 | + res = register_netdev(net); | |
16641 | + if (res) | |
16642 | + goto out3; | |
16643 | + queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | |
16644 | + CARRIER_CHECK_DELAY); | |
16645 | + dev_info(&intf->dev, "%s, %s, %pM\n", net->name, | |
16646 | + usb_dev_id[dev_index].name, net->dev_addr); | |
16647 | + return 0; | |
16648 | + | |
16649 | +out3: | |
16650 | + usb_set_intfdata(intf, NULL); | |
16651 | +out2: | |
16652 | + free_all_urbs(pegasus); | |
16653 | +out1: | |
16654 | + free_netdev(net); | |
16655 | +out: | |
16656 | + pegasus_dec_workqueue(); | |
16657 | + return res; | |
16658 | +} | |
16659 | + | |
16660 | +static void pegasus_disconnect(struct usb_interface *intf) | |
16661 | +{ | |
16662 | + struct pegasus *pegasus = usb_get_intfdata(intf); | |
16663 | + | |
16664 | + usb_set_intfdata(intf, NULL); | |
16665 | + if (!pegasus) { | |
16666 | + dev_dbg(&intf->dev, "unregistering non-bound device?\n"); | |
16667 | + return; | |
16668 | + } | |
16669 | + | |
16670 | + pegasus->flags |= PEGASUS_UNPLUG; | |
16671 | + cancel_delayed_work(&pegasus->carrier_check); | |
16672 | + unregister_netdev(pegasus->net); | |
16673 | + unlink_all_urbs(pegasus); | |
16674 | + free_all_urbs(pegasus); | |
16675 | + if (pegasus->rx_skb != NULL) { | |
16676 | + dev_kfree_skb(pegasus->rx_skb); | |
16677 | + pegasus->rx_skb = NULL; | |
16678 | + } | |
16679 | + free_netdev(pegasus->net); | |
16680 | + pegasus_dec_workqueue(); | |
16681 | +} | |
16682 | + | |
16683 | +static int pegasus_suspend(struct usb_interface *intf, pm_message_t message) | |
16684 | +{ | |
16685 | + struct pegasus *pegasus = usb_get_intfdata(intf); | |
16686 | + | |
16687 | + netif_device_detach(pegasus->net); | |
16688 | + cancel_delayed_work(&pegasus->carrier_check); | |
16689 | + if (netif_running(pegasus->net)) { | |
16690 | + usb_kill_urb(pegasus->rx_urb); | |
16691 | + usb_kill_urb(pegasus->intr_urb); | |
16692 | + } | |
16693 | + return 0; | |
16694 | +} | |
16695 | + | |
16696 | +static int pegasus_resume(struct usb_interface *intf) | |
16697 | +{ | |
16698 | + struct pegasus *pegasus = usb_get_intfdata(intf); | |
16699 | + | |
16700 | + netif_device_attach(pegasus->net); | |
16701 | + if (netif_running(pegasus->net)) { | |
16702 | + pegasus->rx_urb->status = 0; | |
16703 | + pegasus->rx_urb->actual_length = 0; | |
16704 | + read_bulk_callback(pegasus->rx_urb); | |
16705 | + | |
16706 | + pegasus->intr_urb->status = 0; | |
16707 | + pegasus->intr_urb->actual_length = 0; | |
16708 | + intr_callback(pegasus->intr_urb); | |
16709 | + } | |
16710 | + queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, | |
16711 | + CARRIER_CHECK_DELAY); | |
16712 | + return 0; | |
16713 | +} | |
16714 | + | |
16715 | +static const struct net_device_ops pegasus_netdev_ops = { | |
16716 | + .ndo_open = pegasus_open, | |
16717 | + .ndo_stop = pegasus_close, | |
16718 | + .ndo_do_ioctl = pegasus_ioctl, | |
16719 | + .ndo_start_xmit = pegasus_start_xmit, | |
16720 | + .ndo_set_rx_mode = pegasus_set_multicast, | |
16721 | + .ndo_get_stats = pegasus_netdev_stats, | |
16722 | + .ndo_tx_timeout = pegasus_tx_timeout, | |
16723 | + .ndo_change_mtu = eth_change_mtu, | |
16724 | + .ndo_set_mac_address = eth_mac_addr, | |
16725 | + .ndo_validate_addr = eth_validate_addr, | |
16726 | +}; | |
16727 | + | |
16728 | +static struct usb_driver pegasus_driver = { | |
16729 | + .name = driver_name, | |
16730 | + .probe = pegasus_probe, | |
16731 | + .disconnect = pegasus_disconnect, | |
16732 | + .id_table = pegasus_ids, | |
16733 | + .suspend = pegasus_suspend, | |
16734 | + .resume = pegasus_resume, | |
16735 | + .disable_hub_initiated_lpm = 1, | |
16736 | +}; | |
16737 | + | |
16738 | +static void __init parse_id(char *id) | |
16739 | +{ | |
16740 | + unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0; | |
16741 | + char *token, *name = NULL; | |
16742 | + | |
16743 | + if ((token = strsep(&id, ":")) != NULL) | |
16744 | + name = token; | |
16745 | + /* name now points to a null terminated string*/ | |
16746 | + if ((token = strsep(&id, ":")) != NULL) | |
16747 | + vendor_id = simple_strtoul(token, NULL, 16); | |
16748 | + if ((token = strsep(&id, ":")) != NULL) | |
16749 | + device_id = simple_strtoul(token, NULL, 16); | |
16750 | + flags = simple_strtoul(id, NULL, 16); | |
16751 | + pr_info("%s: new device %s, vendor ID 0x%04x, device ID 0x%04x, flags: 0x%x\n", | |
16752 | + driver_name, name, vendor_id, device_id, flags); | |
16753 | + | |
16754 | + if (vendor_id > 0x10000 || vendor_id == 0) | |
16755 | + return; | |
16756 | + if (device_id > 0x10000 || device_id == 0) | |
16757 | + return; | |
16758 | + | |
16759 | + for (i = 0; usb_dev_id[i].name; i++); | |
16760 | + usb_dev_id[i].name = name; | |
16761 | + usb_dev_id[i].vendor = vendor_id; | |
16762 | + usb_dev_id[i].device = device_id; | |
16763 | + usb_dev_id[i].private = flags; | |
16764 | + pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; | |
16765 | + pegasus_ids[i].idVendor = vendor_id; | |
16766 | + pegasus_ids[i].idProduct = device_id; | |
16767 | +} | |
16768 | + | |
16769 | +static int __init pegasus_init(void) | |
16770 | +{ | |
16771 | + pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); | |
16772 | + if (devid) | |
16773 | + parse_id(devid); | |
16774 | + return usb_register(&pegasus_driver); | |
16775 | +} | |
16776 | + | |
16777 | +static void __exit pegasus_exit(void) | |
16778 | +{ | |
16779 | + usb_deregister(&pegasus_driver); | |
16780 | +} | |
16781 | + | |
16782 | +module_init(pegasus_init); | |
16783 | +module_exit(pegasus_exit); | |
16784 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/pegasus.h backports-3.18.1-1/drivers/net/usb/pegasus.h | |
16785 | --- backports-3.18.1-1.org/drivers/net/usb/pegasus.h 1970-01-01 01:00:00.000000000 +0100 | |
16786 | +++ backports-3.18.1-1/drivers/net/usb/pegasus.h 2014-12-16 18:39:45.000000000 +0100 | |
16787 | @@ -0,0 +1,308 @@ | |
16788 | +/* | |
16789 | + * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.com) | |
16790 | + * | |
16791 | + * This program is free software; you can redistribute it and/or modify | |
16792 | + * it under the terms of the GNU General Public License version 2 as published | |
16793 | + * by the Free Software Foundation. | |
16794 | + */ | |
16795 | + | |
16796 | + | |
16797 | +#ifndef PEGASUS_DEV | |
16798 | + | |
16799 | +#define PEGASUS_II 0x80000000 | |
16800 | +#define HAS_HOME_PNA 0x40000000 | |
16801 | + | |
16802 | +#define PEGASUS_MTU 1536 | |
16803 | + | |
16804 | +#define EPROM_WRITE 0x01 | |
16805 | +#define EPROM_READ 0x02 | |
16806 | +#define EPROM_DONE 0x04 | |
16807 | +#define EPROM_WR_ENABLE 0x10 | |
16808 | +#define EPROM_LOAD 0x20 | |
16809 | + | |
16810 | +#define PHY_DONE 0x80 | |
16811 | +#define PHY_READ 0x40 | |
16812 | +#define PHY_WRITE 0x20 | |
16813 | +#define DEFAULT_GPIO_RESET 0x24 | |
16814 | +#define DEFAULT_GPIO_SET 0x26 | |
16815 | + | |
16816 | +#define PEGASUS_PRESENT 0x00000001 | |
16817 | +#define PEGASUS_TX_BUSY 0x00000004 | |
16818 | +#define PEGASUS_RX_BUSY 0x00000008 | |
16819 | +#define CTRL_URB_RUNNING 0x00000010 | |
16820 | +#define CTRL_URB_SLEEP 0x00000020 | |
16821 | +#define PEGASUS_UNPLUG 0x00000040 | |
16822 | +#define PEGASUS_RX_URB_FAIL 0x00000080 | |
16823 | + | |
16824 | +#define RX_MULTICAST 2 | |
16825 | +#define RX_PROMISCUOUS 4 | |
16826 | + | |
16827 | +#define REG_TIMEOUT (HZ) | |
16828 | +#define PEGASUS_TX_TIMEOUT (HZ*10) | |
16829 | + | |
16830 | +#define TX_UNDERRUN 0x80 | |
16831 | +#define EXCESSIVE_COL 0x40 | |
16832 | +#define LATE_COL 0x20 | |
16833 | +#define NO_CARRIER 0x10 | |
16834 | +#define LOSS_CARRIER 0x08 | |
16835 | +#define JABBER_TIMEOUT 0x04 | |
16836 | + | |
16837 | +#define LINK_STATUS 0x01 | |
16838 | + | |
16839 | +#define PEGASUS_REQT_READ 0xc0 | |
16840 | +#define PEGASUS_REQT_WRITE 0x40 | |
16841 | +#define PEGASUS_REQ_GET_REGS 0xf0 | |
16842 | +#define PEGASUS_REQ_SET_REGS 0xf1 | |
16843 | +#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS | |
16844 | + | |
16845 | +enum pegasus_registers { | |
16846 | + EthCtrl0 = 0, | |
16847 | + EthCtrl1 = 1, | |
16848 | + EthCtrl2 = 2, | |
16849 | + EthID = 0x10, | |
16850 | + Reg1d = 0x1d, | |
16851 | + EpromOffset = 0x20, | |
16852 | + EpromData = 0x21, /* 0x21 low, 0x22 high byte */ | |
16853 | + EpromCtrl = 0x23, | |
16854 | + PhyAddr = 0x25, | |
16855 | + PhyData = 0x26, /* 0x26 low, 0x27 high byte */ | |
16856 | + PhyCtrl = 0x28, | |
16857 | + UsbStst = 0x2a, | |
16858 | + EthTxStat0 = 0x2b, | |
16859 | + EthTxStat1 = 0x2c, | |
16860 | + EthRxStat = 0x2d, | |
16861 | + WakeupControl = 0x78, | |
16862 | + Reg7b = 0x7b, | |
16863 | + Gpio0 = 0x7e, | |
16864 | + Gpio1 = 0x7f, | |
16865 | + Reg81 = 0x81, | |
16866 | +}; | |
16867 | + | |
16868 | + | |
16869 | +typedef struct pegasus { | |
16870 | + struct usb_device *usb; | |
16871 | + struct usb_interface *intf; | |
16872 | + struct net_device *net; | |
16873 | + struct net_device_stats stats; | |
16874 | + struct mii_if_info mii; | |
16875 | + unsigned flags; | |
16876 | + unsigned features; | |
16877 | + u32 msg_enable; | |
16878 | + u32 wolopts; | |
16879 | + int dev_index; | |
16880 | + int intr_interval; | |
16881 | + struct tasklet_struct rx_tl; | |
16882 | + struct delayed_work carrier_check; | |
16883 | + struct urb *rx_urb, *tx_urb, *intr_urb; | |
16884 | + struct sk_buff *rx_skb; | |
16885 | + int chip; | |
16886 | + unsigned char intr_buff[8]; | |
16887 | + __u8 tx_buff[PEGASUS_MTU]; | |
16888 | + __u8 eth_regs[4]; | |
16889 | + __u8 phy; | |
16890 | + __u8 gpio_res; | |
16891 | +} pegasus_t; | |
16892 | + | |
16893 | + | |
16894 | +struct usb_eth_dev { | |
16895 | + char *name; | |
16896 | + __u16 vendor; | |
16897 | + __u16 device; | |
16898 | + __u32 private; /* LSB is gpio reset value */ | |
16899 | +}; | |
16900 | + | |
16901 | +#define VENDOR_3COM 0x0506 | |
16902 | +#define VENDOR_ABOCOM 0x07b8 | |
16903 | +#define VENDOR_ACCTON 0x083a | |
16904 | +#define VENDOR_ADMTEK 0x07a6 | |
16905 | +#define VENDOR_AEILAB 0x3334 | |
16906 | +#define VENDOR_ALLIEDTEL 0x07c9 | |
16907 | +#define VENDOR_ATEN 0x0557 | |
16908 | +#define VENDOR_BELKIN 0x050d | |
16909 | +#define VENDOR_BILLIONTON 0x08dd | |
16910 | +#define VENDOR_COMPAQ 0x049f | |
16911 | +#define VENDOR_COREGA 0x07aa | |
16912 | +#define VENDOR_DLINK 0x2001 | |
16913 | +#define VENDOR_ELCON 0x0db7 | |
16914 | +#define VENDOR_ELECOM 0x056e | |
16915 | +#define VENDOR_ELSA 0x05cc | |
16916 | +#define VENDOR_GIGABYTE 0x1044 | |
16917 | +#define VENDOR_HAWKING 0x0e66 | |
16918 | +#define VENDOR_HP 0x03f0 | |
16919 | +#define VENDOR_IODATA 0x04bb | |
16920 | +#define VENDOR_KINGSTON 0x0951 | |
16921 | +#define VENDOR_LANEED 0x056e | |
16922 | +#define VENDOR_LINKSYS 0x066b | |
16923 | +#define VENDOR_LINKSYS2 0x077b | |
16924 | +#define VENDOR_MELCO 0x0411 | |
16925 | +#define VENDOR_MICROSOFT 0x045e | |
16926 | +#define VENDOR_MOBILITY 0x1342 | |
16927 | +#define VENDOR_NETGEAR 0x0846 | |
16928 | +#define VENDOR_OCT 0x0b39 | |
16929 | +#define VENDOR_SMARTBRIDGES 0x08d1 | |
16930 | +#define VENDOR_SMC 0x0707 | |
16931 | +#define VENDOR_SOHOWARE 0x15e8 | |
16932 | +#define VENDOR_SIEMENS 0x067c | |
16933 | + | |
16934 | + | |
16935 | +#else /* PEGASUS_DEV */ | |
16936 | + | |
16937 | +PEGASUS_DEV("3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601, | |
16938 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16939 | +PEGASUS_DEV("ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007, | |
16940 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16941 | +PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c, | |
16942 | + DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA) | |
16943 | +PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104, | |
16944 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
16945 | +PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004, | |
16946 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
16947 | +PEGASUS_DEV("USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007, | |
16948 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
16949 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102, | |
16950 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16951 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002, | |
16952 | + DEFAULT_GPIO_RESET) | |
16953 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b, | |
16954 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16955 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c, | |
16956 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16957 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1, | |
16958 | + DEFAULT_GPIO_RESET) | |
16959 | +PEGASUS_DEV("USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c, | |
16960 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16961 | +PEGASUS_DEV("Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046, | |
16962 | + DEFAULT_GPIO_RESET) | |
16963 | +PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046, | |
16964 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16965 | +PEGASUS_DEV("Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004, | |
16966 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16967 | +PEGASUS_DEV("ADMtek ADM8511 \"Pegasus II\" USB Ethernet", | |
16968 | + VENDOR_ADMTEK, 0x8511, | |
16969 | + DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA) | |
16970 | +PEGASUS_DEV("ADMtek ADM8513 \"Pegasus II\" USB Ethernet", | |
16971 | + VENDOR_ADMTEK, 0x8513, | |
16972 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16973 | +PEGASUS_DEV("ADMtek ADM8515 \"Pegasus II\" USB-2.0 Ethernet", | |
16974 | + VENDOR_ADMTEK, 0x8515, | |
16975 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16976 | +PEGASUS_DEV("ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)", | |
16977 | + VENDOR_ADMTEK, 0x0986, | |
16978 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
16979 | +PEGASUS_DEV("AN986A USB MAC", VENDOR_ADMTEK, 1986, | |
16980 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16981 | +PEGASUS_DEV("AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701, | |
16982 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16983 | +PEGASUS_DEV("Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100, | |
16984 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16985 | +/* | |
16986 | + * Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors | |
16987 | + * with the same product IDs by checking the device class too. | |
16988 | + */ | |
16989 | +PEGASUS_DEV_CLASS("Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00, | |
16990 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16991 | +PEGASUS_DEV("Belkin F5U122 10/100 USB Ethernet", VENDOR_BELKIN, 0x0122, | |
16992 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16993 | +PEGASUS_DEV("Billionton USB-100", VENDOR_BILLIONTON, 0x0986, | |
16994 | + DEFAULT_GPIO_RESET) | |
16995 | +PEGASUS_DEV("Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987, | |
16996 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
16997 | +PEGASUS_DEV("iPAQ Networking 10/100 USB", VENDOR_COMPAQ, 0x8511, | |
16998 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
16999 | +PEGASUS_DEV("Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, | |
17000 | + DEFAULT_GPIO_RESET) | |
17001 | +PEGASUS_DEV("Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, | |
17002 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17003 | +PEGASUS_DEV("Corega FEther USB-TX", VENDOR_COREGA, 0x0004, | |
17004 | + DEFAULT_GPIO_RESET) | |
17005 | +PEGASUS_DEV("Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, | |
17006 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17007 | +PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4001, | |
17008 | + DEFAULT_GPIO_RESET) | |
17009 | +PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4002, | |
17010 | + DEFAULT_GPIO_RESET) | |
17011 | +PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x4102, | |
17012 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17013 | +PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x400b, | |
17014 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17015 | +PEGASUS_DEV("D-Link DSB-650TX", VENDOR_DLINK, 0x200c, | |
17016 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17017 | +PEGASUS_DEV("D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003, | |
17018 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
17019 | +PEGASUS_DEV("D-Link DSB-650", VENDOR_DLINK, 0xabc1, | |
17020 | + DEFAULT_GPIO_RESET) | |
17021 | +PEGASUS_DEV("GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002, | |
17022 | + DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA) | |
17023 | +PEGASUS_DEV("ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010, | |
17024 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17025 | +PEGASUS_DEV("EasiDock Ethernet", VENDOR_MOBILITY, 0x0304, | |
17026 | + DEFAULT_GPIO_RESET) | |
17027 | +PEGASUS_DEV("Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, | |
17028 | + DEFAULT_GPIO_RESET) | |
17029 | +PEGASUS_DEV("GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, | |
17030 | + DEFAULT_GPIO_RESET) | |
17031 | +PEGASUS_DEV("Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, | |
17032 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17033 | +PEGASUS_DEV("HP hn210c Ethernet USB", VENDOR_HP, 0x811c, | |
17034 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17035 | +PEGASUS_DEV("IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, | |
17036 | + DEFAULT_GPIO_RESET) | |
17037 | +PEGASUS_DEV("IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, | |
17038 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17039 | +PEGASUS_DEV("IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a, | |
17040 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17041 | +PEGASUS_DEV("Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a, | |
17042 | + DEFAULT_GPIO_RESET) | |
17043 | +PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002, | |
17044 | + DEFAULT_GPIO_RESET) | |
17045 | +PEGASUS_DEV("LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005, | |
17046 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17047 | +PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b, | |
17048 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17049 | +PEGASUS_DEV("LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1, | |
17050 | + DEFAULT_GPIO_RESET) | |
17051 | +PEGASUS_DEV("LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c, | |
17052 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17053 | +PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x2202, | |
17054 | + DEFAULT_GPIO_RESET) | |
17055 | +PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2203, | |
17056 | + DEFAULT_GPIO_RESET) | |
17057 | +PEGASUS_DEV("Linksys USB100TX", VENDOR_LINKSYS, 0x2204, | |
17058 | + DEFAULT_GPIO_RESET | HAS_HOME_PNA) | |
17059 | +PEGASUS_DEV("Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206, | |
17060 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17061 | +PEGASUS_DEV("Linksys USBVPN1", VENDOR_LINKSYS2, 0x08b4, | |
17062 | + DEFAULT_GPIO_RESET) | |
17063 | +PEGASUS_DEV("Linksys USB USB100TX", VENDOR_LINKSYS, 0x400b, | |
17064 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17065 | +PEGASUS_DEV("Linksys USB10TX", VENDOR_LINKSYS, 0x200c, | |
17066 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17067 | +PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001, | |
17068 | + DEFAULT_GPIO_RESET) | |
17069 | +PEGASUS_DEV("MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005, | |
17070 | + DEFAULT_GPIO_RESET) | |
17071 | +PEGASUS_DEV("MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009, | |
17072 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17073 | +PEGASUS_DEV("Microsoft MN-110", VENDOR_MICROSOFT, 0x007a, | |
17074 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17075 | +PEGASUS_DEV("NETGEAR FA101", VENDOR_NETGEAR, 0x1020, | |
17076 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17077 | +PEGASUS_DEV("OCT Inc.", VENDOR_OCT, 0x0109, | |
17078 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17079 | +PEGASUS_DEV("OCT USB TO Ethernet", VENDOR_OCT, 0x0901, | |
17080 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17081 | +PEGASUS_DEV("smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, | |
17082 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17083 | +PEGASUS_DEV("SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, | |
17084 | + DEFAULT_GPIO_RESET) | |
17085 | +PEGASUS_DEV("SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201, | |
17086 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17087 | +PEGASUS_DEV("SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100, | |
17088 | + DEFAULT_GPIO_RESET) | |
17089 | +PEGASUS_DEV("SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110, | |
17090 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17091 | +PEGASUS_DEV("SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001, | |
17092 | + DEFAULT_GPIO_RESET | PEGASUS_II) | |
17093 | + | |
17094 | + | |
17095 | +#endif /* PEGASUS_DEV */ | |
17096 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/plusb.c backports-3.18.1-1/drivers/net/usb/plusb.c | |
17097 | --- backports-3.18.1-1.org/drivers/net/usb/plusb.c 1970-01-01 01:00:00.000000000 +0100 | |
17098 | +++ backports-3.18.1-1/drivers/net/usb/plusb.c 2014-12-16 18:39:45.000000000 +0100 | |
17099 | @@ -0,0 +1,157 @@ | |
17100 | +/* | |
17101 | + * PL-2301/2302 USB host-to-host link cables | |
17102 | + * Copyright (C) 2000-2005 by David Brownell | |
17103 | + * | |
17104 | + * This program is free software; you can redistribute it and/or modify | |
17105 | + * it under the terms of the GNU General Public License as published by | |
17106 | + * the Free Software Foundation; either version 2 of the License, or | |
17107 | + * (at your option) any later version. | |
17108 | + * | |
17109 | + * This program is distributed in the hope that it will be useful, | |
17110 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17111 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17112 | + * GNU General Public License for more details. | |
17113 | + * | |
17114 | + * You should have received a copy of the GNU General Public License | |
17115 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
17116 | + */ | |
17117 | + | |
17118 | +// #define DEBUG // error path messages, extra info | |
17119 | +// #define VERBOSE // more; success messages | |
17120 | + | |
17121 | +#include <linux/module.h> | |
17122 | +#include <linux/netdevice.h> | |
17123 | +#include <linux/etherdevice.h> | |
17124 | +#include <linux/ethtool.h> | |
17125 | +#include <linux/workqueue.h> | |
17126 | +#include <linux/mii.h> | |
17127 | +#include <linux/usb.h> | |
17128 | +#include <linux/usb/usbnet.h> | |
17129 | + | |
17130 | + | |
17131 | +/* | |
17132 | + * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/ | |
17133 | + * | |
17134 | + * The protocol and handshaking used here should be bug-compatible | |
17135 | + * with the Linux 2.2 "plusb" driver, by Deti Fliegl. | |
17136 | + * | |
17137 | + * HEADS UP: this handshaking isn't all that robust. This driver | |
17138 | + * gets confused easily if you unplug one end of the cable then | |
17139 | + * try to connect it again; you'll need to restart both ends. The | |
17140 | + * "naplink" software (used by some PlayStation/2 deveopers) does | |
17141 | + * the handshaking much better! Also, sometimes this hardware | |
17142 | + * seems to get wedged under load. Prolific docs are weak, and | |
17143 | + * don't identify differences between PL2301 and PL2302, much less | |
17144 | + * anything to explain the different PL2302 versions observed. | |
17145 | + * | |
17146 | + * NOTE: pl2501 has several modes, including pl2301 and pl2302 | |
17147 | + * compatibility. Some docs suggest the difference between 2301 | |
17148 | + * and 2302 is only to make MS-Windows use a different driver... | |
17149 | + * | |
17150 | + * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on | |
17151 | + * this chip are as usual incomplete about what control messages | |
17152 | + * are supported. | |
17153 | + */ | |
17154 | + | |
17155 | +/* | |
17156 | + * Bits 0-4 can be used for software handshaking; they're set from | |
17157 | + * one end, cleared from the other, "read" with the interrupt byte. | |
17158 | + */ | |
17159 | +#define PL_S_EN (1<<7) /* (feature only) suspend enable */ | |
17160 | +/* reserved bit -- rx ready (6) ? */ | |
17161 | +#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */ | |
17162 | +#define PL_RESET_OUT (1<<4) /* reset output pipe */ | |
17163 | +#define PL_RESET_IN (1<<3) /* reset input pipe */ | |
17164 | +#define PL_TX_C (1<<2) /* transmission complete */ | |
17165 | +#define PL_TX_REQ (1<<1) /* transmission received */ | |
17166 | +#define PL_PEER_E (1<<0) /* peer exists */ | |
17167 | + | |
17168 | +static inline int | |
17169 | +pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index) | |
17170 | +{ | |
17171 | + return usbnet_read_cmd(dev, req, | |
17172 | + USB_DIR_IN | USB_TYPE_VENDOR | | |
17173 | + USB_RECIP_DEVICE, | |
17174 | + val, index, NULL, 0); | |
17175 | +} | |
17176 | + | |
17177 | +static inline int | |
17178 | +pl_clear_QuickLink_features(struct usbnet *dev, int val) | |
17179 | +{ | |
17180 | + return pl_vendor_req(dev, 1, (u8) val, 0); | |
17181 | +} | |
17182 | + | |
17183 | +static inline int | |
17184 | +pl_set_QuickLink_features(struct usbnet *dev, int val) | |
17185 | +{ | |
17186 | + return pl_vendor_req(dev, 3, (u8) val, 0); | |
17187 | +} | |
17188 | + | |
17189 | +static int pl_reset(struct usbnet *dev) | |
17190 | +{ | |
17191 | + int status; | |
17192 | + | |
17193 | + /* some units seem to need this reset, others reject it utterly. | |
17194 | + * FIXME be more like "naplink" or windows drivers. | |
17195 | + */ | |
17196 | + status = pl_set_QuickLink_features(dev, | |
17197 | + PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); | |
17198 | + if (status != 0 && netif_msg_probe(dev)) | |
17199 | + netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); | |
17200 | + return 0; | |
17201 | +} | |
17202 | + | |
17203 | +static const struct driver_info prolific_info = { | |
17204 | + .description = "Prolific PL-2301/PL-2302/PL-25A1", | |
17205 | + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, | |
17206 | + /* some PL-2302 versions seem to fail usb_set_interface() */ | |
17207 | + .reset = pl_reset, | |
17208 | +}; | |
17209 | + | |
17210 | + | |
17211 | +/*-------------------------------------------------------------------------*/ | |
17212 | + | |
17213 | +/* | |
17214 | + * Proilific's name won't normally be on the cables, and | |
17215 | + * may not be on the device. | |
17216 | + */ | |
17217 | + | |
17218 | +static const struct usb_device_id products [] = { | |
17219 | + | |
17220 | +/* full speed cables */ | |
17221 | +{ | |
17222 | + USB_DEVICE(0x067b, 0x0000), // PL-2301 | |
17223 | + .driver_info = (unsigned long) &prolific_info, | |
17224 | +}, { | |
17225 | + USB_DEVICE(0x067b, 0x0001), // PL-2302 | |
17226 | + .driver_info = (unsigned long) &prolific_info, | |
17227 | +}, | |
17228 | + | |
17229 | +/* high speed cables */ | |
17230 | +{ | |
17231 | + USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ | |
17232 | + .driver_info = (unsigned long) &prolific_info, | |
17233 | +}, { | |
17234 | + USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ | |
17235 | + .driver_info = (unsigned long) &prolific_info, | |
17236 | +}, | |
17237 | + | |
17238 | + { }, // END | |
17239 | +}; | |
17240 | +MODULE_DEVICE_TABLE(usb, products); | |
17241 | + | |
17242 | +static struct usb_driver plusb_driver = { | |
17243 | + .name = "plusb", | |
17244 | + .id_table = products, | |
17245 | + .probe = usbnet_probe, | |
17246 | + .disconnect = usbnet_disconnect, | |
17247 | + .suspend = usbnet_suspend, | |
17248 | + .resume = usbnet_resume, | |
17249 | + .disable_hub_initiated_lpm = 1, | |
17250 | +}; | |
17251 | + | |
17252 | +module_usb_driver(plusb_driver); | |
17253 | + | |
17254 | +MODULE_AUTHOR("David Brownell"); | |
17255 | +MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); | |
17256 | +MODULE_LICENSE("GPL"); | |
17257 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/r8152.c backports-3.18.1-1/drivers/net/usb/r8152.c | |
17258 | --- backports-3.18.1-1.org/drivers/net/usb/r8152.c 1970-01-01 01:00:00.000000000 +0100 | |
17259 | +++ backports-3.18.1-1/drivers/net/usb/r8152.c 2015-01-03 13:42:25.000000000 +0100 | |
17260 | @@ -0,0 +1,3913 @@ | |
17261 | +/* | |
17262 | + * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. | |
17263 | + * | |
17264 | + * This program is free software; you can redistribute it and/or | |
17265 | + * modify it under the terms of the GNU General Public License | |
17266 | + * version 2 as published by the Free Software Foundation. | |
17267 | + * | |
17268 | + */ | |
17269 | + | |
17270 | +#include <linux/signal.h> | |
17271 | +#include <linux/slab.h> | |
17272 | +#include <linux/module.h> | |
17273 | +#include <linux/netdevice.h> | |
17274 | +#include <linux/etherdevice.h> | |
17275 | +#include <linux/mii.h> | |
17276 | +#include <linux/ethtool.h> | |
17277 | +#include <linux/usb.h> | |
17278 | +#include <linux/crc32.h> | |
17279 | +#include <linux/if_vlan.h> | |
17280 | +#include <linux/uaccess.h> | |
17281 | +#include <linux/list.h> | |
17282 | +#include <linux/ip.h> | |
17283 | +#include <linux/ipv6.h> | |
17284 | +#include <net/ip6_checksum.h> | |
17285 | +#include <uapi/linux/mdio.h> | |
17286 | +#include <linux/mdio.h> | |
17287 | + | |
17288 | +/* Version Information */ | |
17289 | +#define DRIVER_VERSION "v1.07.0 (2014/10/09)" | |
17290 | +#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" | |
17291 | +#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" | |
17292 | +#define MODULENAME "r8152" | |
17293 | + | |
17294 | +#define R8152_PHY_ID 32 | |
17295 | + | |
17296 | +#define PLA_IDR 0xc000 | |
17297 | +#define PLA_RCR 0xc010 | |
17298 | +#define PLA_RMS 0xc016 | |
17299 | +#define PLA_RXFIFO_CTRL0 0xc0a0 | |
17300 | +#define PLA_RXFIFO_CTRL1 0xc0a4 | |
17301 | +#define PLA_RXFIFO_CTRL2 0xc0a8 | |
17302 | +#define PLA_FMC 0xc0b4 | |
17303 | +#define PLA_CFG_WOL 0xc0b6 | |
17304 | +#define PLA_TEREDO_CFG 0xc0bc | |
17305 | +#define PLA_MAR 0xcd00 | |
17306 | +#define PLA_BACKUP 0xd000 | |
17307 | +#define PAL_BDC_CR 0xd1a0 | |
17308 | +#define PLA_TEREDO_TIMER 0xd2cc | |
17309 | +#define PLA_REALWOW_TIMER 0xd2e8 | |
17310 | +#define PLA_LEDSEL 0xdd90 | |
17311 | +#define PLA_LED_FEATURE 0xdd92 | |
17312 | +#define PLA_PHYAR 0xde00 | |
17313 | +#define PLA_BOOT_CTRL 0xe004 | |
17314 | +#define PLA_GPHY_INTR_IMR 0xe022 | |
17315 | +#define PLA_EEE_CR 0xe040 | |
17316 | +#define PLA_EEEP_CR 0xe080 | |
17317 | +#define PLA_MAC_PWR_CTRL 0xe0c0 | |
17318 | +#define PLA_MAC_PWR_CTRL2 0xe0ca | |
17319 | +#define PLA_MAC_PWR_CTRL3 0xe0cc | |
17320 | +#define PLA_MAC_PWR_CTRL4 0xe0ce | |
17321 | +#define PLA_WDT6_CTRL 0xe428 | |
17322 | +#define PLA_TCR0 0xe610 | |
17323 | +#define PLA_TCR1 0xe612 | |
17324 | +#define PLA_MTPS 0xe615 | |
17325 | +#define PLA_TXFIFO_CTRL 0xe618 | |
17326 | +#define PLA_RSTTALLY 0xe800 | |
17327 | +#define PLA_CR 0xe813 | |
17328 | +#define PLA_CRWECR 0xe81c | |
17329 | +#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ | |
17330 | +#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */ | |
17331 | +#define PLA_CONFIG5 0xe822 | |
17332 | +#define PLA_PHY_PWR 0xe84c | |
17333 | +#define PLA_OOB_CTRL 0xe84f | |
17334 | +#define PLA_CPCR 0xe854 | |
17335 | +#define PLA_MISC_0 0xe858 | |
17336 | +#define PLA_MISC_1 0xe85a | |
17337 | +#define PLA_OCP_GPHY_BASE 0xe86c | |
17338 | +#define PLA_TALLYCNT 0xe890 | |
17339 | +#define PLA_SFF_STS_7 0xe8de | |
17340 | +#define PLA_PHYSTATUS 0xe908 | |
17341 | +#define PLA_BP_BA 0xfc26 | |
17342 | +#define PLA_BP_0 0xfc28 | |
17343 | +#define PLA_BP_1 0xfc2a | |
17344 | +#define PLA_BP_2 0xfc2c | |
17345 | +#define PLA_BP_3 0xfc2e | |
17346 | +#define PLA_BP_4 0xfc30 | |
17347 | +#define PLA_BP_5 0xfc32 | |
17348 | +#define PLA_BP_6 0xfc34 | |
17349 | +#define PLA_BP_7 0xfc36 | |
17350 | +#define PLA_BP_EN 0xfc38 | |
17351 | + | |
17352 | +#define USB_U2P3_CTRL 0xb460 | |
17353 | +#define USB_DEV_STAT 0xb808 | |
17354 | +#define USB_USB_CTRL 0xd406 | |
17355 | +#define USB_PHY_CTRL 0xd408 | |
17356 | +#define USB_TX_AGG 0xd40a | |
17357 | +#define USB_RX_BUF_TH 0xd40c | |
17358 | +#define USB_USB_TIMER 0xd428 | |
17359 | +#define USB_RX_EARLY_AGG 0xd42c | |
17360 | +#define USB_PM_CTRL_STATUS 0xd432 | |
17361 | +#define USB_TX_DMA 0xd434 | |
17362 | +#define USB_TOLERANCE 0xd490 | |
17363 | +#define USB_LPM_CTRL 0xd41a | |
17364 | +#define USB_UPS_CTRL 0xd800 | |
17365 | +#define USB_MISC_0 0xd81a | |
17366 | +#define USB_POWER_CUT 0xd80a | |
17367 | +#define USB_AFE_CTRL2 0xd824 | |
17368 | +#define USB_WDT11_CTRL 0xe43c | |
17369 | +#define USB_BP_BA 0xfc26 | |
17370 | +#define USB_BP_0 0xfc28 | |
17371 | +#define USB_BP_1 0xfc2a | |
17372 | +#define USB_BP_2 0xfc2c | |
17373 | +#define USB_BP_3 0xfc2e | |
17374 | +#define USB_BP_4 0xfc30 | |
17375 | +#define USB_BP_5 0xfc32 | |
17376 | +#define USB_BP_6 0xfc34 | |
17377 | +#define USB_BP_7 0xfc36 | |
17378 | +#define USB_BP_EN 0xfc38 | |
17379 | + | |
17380 | +/* OCP Registers */ | |
17381 | +#define OCP_ALDPS_CONFIG 0x2010 | |
17382 | +#define OCP_EEE_CONFIG1 0x2080 | |
17383 | +#define OCP_EEE_CONFIG2 0x2092 | |
17384 | +#define OCP_EEE_CONFIG3 0x2094 | |
17385 | +#define OCP_BASE_MII 0xa400 | |
17386 | +#define OCP_EEE_AR 0xa41a | |
17387 | +#define OCP_EEE_DATA 0xa41c | |
17388 | +#define OCP_PHY_STATUS 0xa420 | |
17389 | +#define OCP_POWER_CFG 0xa430 | |
17390 | +#define OCP_EEE_CFG 0xa432 | |
17391 | +#define OCP_SRAM_ADDR 0xa436 | |
17392 | +#define OCP_SRAM_DATA 0xa438 | |
17393 | +#define OCP_DOWN_SPEED 0xa442 | |
17394 | +#define OCP_EEE_ABLE 0xa5c4 | |
17395 | +#define OCP_EEE_ADV 0xa5d0 | |
17396 | +#define OCP_EEE_LPABLE 0xa5d2 | |
17397 | +#define OCP_ADC_CFG 0xbc06 | |
17398 | + | |
17399 | +/* SRAM Register */ | |
17400 | +#define SRAM_LPF_CFG 0x8012 | |
17401 | +#define SRAM_10M_AMP1 0x8080 | |
17402 | +#define SRAM_10M_AMP2 0x8082 | |
17403 | +#define SRAM_IMPEDANCE 0x8084 | |
17404 | + | |
17405 | +/* PLA_RCR */ | |
17406 | +#define RCR_AAP 0x00000001 | |
17407 | +#define RCR_APM 0x00000002 | |
17408 | +#define RCR_AM 0x00000004 | |
17409 | +#define RCR_AB 0x00000008 | |
17410 | +#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB) | |
17411 | + | |
17412 | +/* PLA_RXFIFO_CTRL0 */ | |
17413 | +#define RXFIFO_THR1_NORMAL 0x00080002 | |
17414 | +#define RXFIFO_THR1_OOB 0x01800003 | |
17415 | + | |
17416 | +/* PLA_RXFIFO_CTRL1 */ | |
17417 | +#define RXFIFO_THR2_FULL 0x00000060 | |
17418 | +#define RXFIFO_THR2_HIGH 0x00000038 | |
17419 | +#define RXFIFO_THR2_OOB 0x0000004a | |
17420 | +#define RXFIFO_THR2_NORMAL 0x00a0 | |
17421 | + | |
17422 | +/* PLA_RXFIFO_CTRL2 */ | |
17423 | +#define RXFIFO_THR3_FULL 0x00000078 | |
17424 | +#define RXFIFO_THR3_HIGH 0x00000048 | |
17425 | +#define RXFIFO_THR3_OOB 0x0000005a | |
17426 | +#define RXFIFO_THR3_NORMAL 0x0110 | |
17427 | + | |
17428 | +/* PLA_TXFIFO_CTRL */ | |
17429 | +#define TXFIFO_THR_NORMAL 0x00400008 | |
17430 | +#define TXFIFO_THR_NORMAL2 0x01000008 | |
17431 | + | |
17432 | +/* PLA_FMC */ | |
17433 | +#define FMC_FCR_MCU_EN 0x0001 | |
17434 | + | |
17435 | +/* PLA_EEEP_CR */ | |
17436 | +#define EEEP_CR_EEEP_TX 0x0002 | |
17437 | + | |
17438 | +/* PLA_WDT6_CTRL */ | |
17439 | +#define WDT6_SET_MODE 0x0010 | |
17440 | + | |
17441 | +/* PLA_TCR0 */ | |
17442 | +#define TCR0_TX_EMPTY 0x0800 | |
17443 | +#define TCR0_AUTO_FIFO 0x0080 | |
17444 | + | |
17445 | +/* PLA_TCR1 */ | |
17446 | +#define VERSION_MASK 0x7cf0 | |
17447 | + | |
17448 | +/* PLA_MTPS */ | |
17449 | +#define MTPS_JUMBO (12 * 1024 / 64) | |
17450 | +#define MTPS_DEFAULT (6 * 1024 / 64) | |
17451 | + | |
17452 | +/* PLA_RSTTALLY */ | |
17453 | +#define TALLY_RESET 0x0001 | |
17454 | + | |
17455 | +/* PLA_CR */ | |
17456 | +#define CR_RST 0x10 | |
17457 | +#define CR_RE 0x08 | |
17458 | +#define CR_TE 0x04 | |
17459 | + | |
17460 | +/* PLA_CRWECR */ | |
17461 | +#define CRWECR_NORAML 0x00 | |
17462 | +#define CRWECR_CONFIG 0xc0 | |
17463 | + | |
17464 | +/* PLA_OOB_CTRL */ | |
17465 | +#define NOW_IS_OOB 0x80 | |
17466 | +#define TXFIFO_EMPTY 0x20 | |
17467 | +#define RXFIFO_EMPTY 0x10 | |
17468 | +#define LINK_LIST_READY 0x02 | |
17469 | +#define DIS_MCU_CLROOB 0x01 | |
17470 | +#define FIFO_EMPTY (TXFIFO_EMPTY | RXFIFO_EMPTY) | |
17471 | + | |
17472 | +/* PLA_MISC_1 */ | |
17473 | +#define RXDY_GATED_EN 0x0008 | |
17474 | + | |
17475 | +/* PLA_SFF_STS_7 */ | |
17476 | +#define RE_INIT_LL 0x8000 | |
17477 | +#define MCU_BORW_EN 0x4000 | |
17478 | + | |
17479 | +/* PLA_CPCR */ | |
17480 | +#define CPCR_RX_VLAN 0x0040 | |
17481 | + | |
17482 | +/* PLA_CFG_WOL */ | |
17483 | +#define MAGIC_EN 0x0001 | |
17484 | + | |
17485 | +/* PLA_TEREDO_CFG */ | |
17486 | +#define TEREDO_SEL 0x8000 | |
17487 | +#define TEREDO_WAKE_MASK 0x7f00 | |
17488 | +#define TEREDO_RS_EVENT_MASK 0x00fe | |
17489 | +#define OOB_TEREDO_EN 0x0001 | |
17490 | + | |
17491 | +/* PAL_BDC_CR */ | |
17492 | +#define ALDPS_PROXY_MODE 0x0001 | |
17493 | + | |
17494 | +/* PLA_CONFIG34 */ | |
17495 | +#define LINK_ON_WAKE_EN 0x0010 | |
17496 | +#define LINK_OFF_WAKE_EN 0x0008 | |
17497 | + | |
17498 | +/* PLA_CONFIG5 */ | |
17499 | +#define BWF_EN 0x0040 | |
17500 | +#define MWF_EN 0x0020 | |
17501 | +#define UWF_EN 0x0010 | |
17502 | +#define LAN_WAKE_EN 0x0002 | |
17503 | + | |
17504 | +/* PLA_LED_FEATURE */ | |
17505 | +#define LED_MODE_MASK 0x0700 | |
17506 | + | |
17507 | +/* PLA_PHY_PWR */ | |
17508 | +#define TX_10M_IDLE_EN 0x0080 | |
17509 | +#define PFM_PWM_SWITCH 0x0040 | |
17510 | + | |
17511 | +/* PLA_MAC_PWR_CTRL */ | |
17512 | +#define D3_CLK_GATED_EN 0x00004000 | |
17513 | +#define MCU_CLK_RATIO 0x07010f07 | |
17514 | +#define MCU_CLK_RATIO_MASK 0x0f0f0f0f | |
17515 | +#define ALDPS_SPDWN_RATIO 0x0f87 | |
17516 | + | |
17517 | +/* PLA_MAC_PWR_CTRL2 */ | |
17518 | +#define EEE_SPDWN_RATIO 0x8007 | |
17519 | + | |
17520 | +/* PLA_MAC_PWR_CTRL3 */ | |
17521 | +#define PKT_AVAIL_SPDWN_EN 0x0100 | |
17522 | +#define SUSPEND_SPDWN_EN 0x0004 | |
17523 | +#define U1U2_SPDWN_EN 0x0002 | |
17524 | +#define L1_SPDWN_EN 0x0001 | |
17525 | + | |
17526 | +/* PLA_MAC_PWR_CTRL4 */ | |
17527 | +#define PWRSAVE_SPDWN_EN 0x1000 | |
17528 | +#define RXDV_SPDWN_EN 0x0800 | |
17529 | +#define TX10MIDLE_EN 0x0100 | |
17530 | +#define TP100_SPDWN_EN 0x0020 | |
17531 | +#define TP500_SPDWN_EN 0x0010 | |
17532 | +#define TP1000_SPDWN_EN 0x0008 | |
17533 | +#define EEE_SPDWN_EN 0x0001 | |
17534 | + | |
17535 | +/* PLA_GPHY_INTR_IMR */ | |
17536 | +#define GPHY_STS_MSK 0x0001 | |
17537 | +#define SPEED_DOWN_MSK 0x0002 | |
17538 | +#define SPDWN_RXDV_MSK 0x0004 | |
17539 | +#define SPDWN_LINKCHG_MSK 0x0008 | |
17540 | + | |
17541 | +/* PLA_PHYAR */ | |
17542 | +#define PHYAR_FLAG 0x80000000 | |
17543 | + | |
17544 | +/* PLA_EEE_CR */ | |
17545 | +#define EEE_RX_EN 0x0001 | |
17546 | +#define EEE_TX_EN 0x0002 | |
17547 | + | |
17548 | +/* PLA_BOOT_CTRL */ | |
17549 | +#define AUTOLOAD_DONE 0x0002 | |
17550 | + | |
17551 | +/* USB_DEV_STAT */ | |
17552 | +#define STAT_SPEED_MASK 0x0006 | |
17553 | +#define STAT_SPEED_HIGH 0x0000 | |
17554 | +#define STAT_SPEED_FULL 0x0002 | |
17555 | + | |
17556 | +/* USB_TX_AGG */ | |
17557 | +#define TX_AGG_MAX_THRESHOLD 0x03 | |
17558 | + | |
17559 | +/* USB_RX_BUF_TH */ | |
17560 | +#define RX_THR_SUPPER 0x0c350180 | |
17561 | +#define RX_THR_HIGH 0x7a120180 | |
17562 | +#define RX_THR_SLOW 0xffff0180 | |
17563 | + | |
17564 | +/* USB_TX_DMA */ | |
17565 | +#define TEST_MODE_DISABLE 0x00000001 | |
17566 | +#define TX_SIZE_ADJUST1 0x00000100 | |
17567 | + | |
17568 | +/* USB_UPS_CTRL */ | |
17569 | +#define POWER_CUT 0x0100 | |
17570 | + | |
17571 | +/* USB_PM_CTRL_STATUS */ | |
17572 | +#define RESUME_INDICATE 0x0001 | |
17573 | + | |
17574 | +/* USB_USB_CTRL */ | |
17575 | +#define RX_AGG_DISABLE 0x0010 | |
17576 | + | |
17577 | +/* USB_U2P3_CTRL */ | |
17578 | +#define U2P3_ENABLE 0x0001 | |
17579 | + | |
17580 | +/* USB_POWER_CUT */ | |
17581 | +#define PWR_EN 0x0001 | |
17582 | +#define PHASE2_EN 0x0008 | |
17583 | + | |
17584 | +/* USB_MISC_0 */ | |
17585 | +#define PCUT_STATUS 0x0001 | |
17586 | + | |
17587 | +/* USB_RX_EARLY_AGG */ | |
17588 | +#define EARLY_AGG_SUPPER 0x0e832981 | |
17589 | +#define EARLY_AGG_HIGH 0x0e837a12 | |
17590 | +#define EARLY_AGG_SLOW 0x0e83ffff | |
17591 | + | |
17592 | +/* USB_WDT11_CTRL */ | |
17593 | +#define TIMER11_EN 0x0001 | |
17594 | + | |
17595 | +/* USB_LPM_CTRL */ | |
17596 | +#define LPM_TIMER_MASK 0x0c | |
17597 | +#define LPM_TIMER_500MS 0x04 /* 500 ms */ | |
17598 | +#define LPM_TIMER_500US 0x0c /* 500 us */ | |
17599 | + | |
17600 | +/* USB_AFE_CTRL2 */ | |
17601 | +#define SEN_VAL_MASK 0xf800 | |
17602 | +#define SEN_VAL_NORMAL 0xa000 | |
17603 | +#define SEL_RXIDLE 0x0100 | |
17604 | + | |
17605 | +/* OCP_ALDPS_CONFIG */ | |
17606 | +#define ENPWRSAVE 0x8000 | |
17607 | +#define ENPDNPS 0x0200 | |
17608 | +#define LINKENA 0x0100 | |
17609 | +#define DIS_SDSAVE 0x0010 | |
17610 | + | |
17611 | +/* OCP_PHY_STATUS */ | |
17612 | +#define PHY_STAT_MASK 0x0007 | |
17613 | +#define PHY_STAT_LAN_ON 3 | |
17614 | +#define PHY_STAT_PWRDN 5 | |
17615 | + | |
17616 | +/* OCP_POWER_CFG */ | |
17617 | +#define EEE_CLKDIV_EN 0x8000 | |
17618 | +#define EN_ALDPS 0x0004 | |
17619 | +#define EN_10M_PLLOFF 0x0001 | |
17620 | + | |
17621 | +/* OCP_EEE_CONFIG1 */ | |
17622 | +#define RG_TXLPI_MSK_HFDUP 0x8000 | |
17623 | +#define RG_MATCLR_EN 0x4000 | |
17624 | +#define EEE_10_CAP 0x2000 | |
17625 | +#define EEE_NWAY_EN 0x1000 | |
17626 | +#define TX_QUIET_EN 0x0200 | |
17627 | +#define RX_QUIET_EN 0x0100 | |
17628 | +#define sd_rise_time_mask 0x0070 | |
17629 | +#define sd_rise_time(x) (min(x, 7) << 4) /* bit 4 ~ 6 */ | |
17630 | +#define RG_RXLPI_MSK_HFDUP 0x0008 | |
17631 | +#define SDFALLTIME 0x0007 /* bit 0 ~ 2 */ | |
17632 | + | |
17633 | +/* OCP_EEE_CONFIG2 */ | |
17634 | +#define RG_LPIHYS_NUM 0x7000 /* bit 12 ~ 15 */ | |
17635 | +#define RG_DACQUIET_EN 0x0400 | |
17636 | +#define RG_LDVQUIET_EN 0x0200 | |
17637 | +#define RG_CKRSEL 0x0020 | |
17638 | +#define RG_EEEPRG_EN 0x0010 | |
17639 | + | |
17640 | +/* OCP_EEE_CONFIG3 */ | |
17641 | +#define fast_snr_mask 0xff80 | |
17642 | +#define fast_snr(x) (min(x, 0x1ff) << 7) /* bit 7 ~ 15 */ | |
17643 | +#define RG_LFS_SEL 0x0060 /* bit 6 ~ 5 */ | |
17644 | +#define MSK_PH 0x0006 /* bit 0 ~ 3 */ | |
17645 | + | |
17646 | +/* OCP_EEE_AR */ | |
17647 | +/* bit[15:14] function */ | |
17648 | +#define FUN_ADDR 0x0000 | |
17649 | +#define FUN_DATA 0x4000 | |
17650 | +/* bit[4:0] device addr */ | |
17651 | + | |
17652 | +/* OCP_EEE_CFG */ | |
17653 | +#define CTAP_SHORT_EN 0x0040 | |
17654 | +#define EEE10_EN 0x0010 | |
17655 | + | |
17656 | +/* OCP_DOWN_SPEED */ | |
17657 | +#define EN_10M_BGOFF 0x0080 | |
17658 | + | |
17659 | +/* OCP_ADC_CFG */ | |
17660 | +#define CKADSEL_L 0x0100 | |
17661 | +#define ADC_EN 0x0080 | |
17662 | +#define EN_EMI_L 0x0040 | |
17663 | + | |
17664 | +/* SRAM_LPF_CFG */ | |
17665 | +#define LPF_AUTO_TUNE 0x8000 | |
17666 | + | |
17667 | +/* SRAM_10M_AMP1 */ | |
17668 | +#define GDAC_IB_UPALL 0x0008 | |
17669 | + | |
17670 | +/* SRAM_10M_AMP2 */ | |
17671 | +#define AMP_DN 0x0200 | |
17672 | + | |
17673 | +/* SRAM_IMPEDANCE */ | |
17674 | +#define RX_DRIVING_MASK 0x6000 | |
17675 | + | |
17676 | +enum rtl_register_content { | |
17677 | + _1000bps = 0x10, | |
17678 | + _100bps = 0x08, | |
17679 | + _10bps = 0x04, | |
17680 | + LINK_STATUS = 0x02, | |
17681 | + FULL_DUP = 0x01, | |
17682 | +}; | |
17683 | + | |
17684 | +#define RTL8152_MAX_TX 4 | |
17685 | +#define RTL8152_MAX_RX 10 | |
17686 | +#define INTBUFSIZE 2 | |
17687 | +#define CRC_SIZE 4 | |
17688 | +#define TX_ALIGN 4 | |
17689 | +#define RX_ALIGN 8 | |
17690 | + | |
17691 | +#define INTR_LINK 0x0004 | |
17692 | + | |
17693 | +#define RTL8152_REQT_READ 0xc0 | |
17694 | +#define RTL8152_REQT_WRITE 0x40 | |
17695 | +#define RTL8152_REQ_GET_REGS 0x05 | |
17696 | +#define RTL8152_REQ_SET_REGS 0x05 | |
17697 | + | |
17698 | +#define BYTE_EN_DWORD 0xff | |
17699 | +#define BYTE_EN_WORD 0x33 | |
17700 | +#define BYTE_EN_BYTE 0x11 | |
17701 | +#define BYTE_EN_SIX_BYTES 0x3f | |
17702 | +#define BYTE_EN_START_MASK 0x0f | |
17703 | +#define BYTE_EN_END_MASK 0xf0 | |
17704 | + | |
17705 | +#define RTL8153_MAX_PACKET 9216 /* 9K */ | |
17706 | +#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) | |
17707 | +#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) | |
17708 | +#define RTL8153_RMS RTL8153_MAX_PACKET | |
17709 | +#define RTL8152_TX_TIMEOUT (5 * HZ) | |
17710 | + | |
17711 | +/* rtl8152 flags */ | |
17712 | +enum rtl8152_flags { | |
17713 | + RTL8152_UNPLUG = 0, | |
17714 | + RTL8152_SET_RX_MODE, | |
17715 | + WORK_ENABLE, | |
17716 | + RTL8152_LINK_CHG, | |
17717 | + SELECTIVE_SUSPEND, | |
17718 | + PHY_RESET, | |
17719 | + SCHEDULE_TASKLET, | |
17720 | +}; | |
17721 | + | |
17722 | +/* Define these values to match your device */ | |
17723 | +#define VENDOR_ID_REALTEK 0x0bda | |
17724 | +#define PRODUCT_ID_RTL8152 0x8152 | |
17725 | +#define PRODUCT_ID_RTL8153 0x8153 | |
17726 | + | |
17727 | +#define VENDOR_ID_SAMSUNG 0x04e8 | |
17728 | +#define PRODUCT_ID_SAMSUNG 0xa101 | |
17729 | + | |
17730 | +#define MCU_TYPE_PLA 0x0100 | |
17731 | +#define MCU_TYPE_USB 0x0000 | |
17732 | + | |
17733 | +#define REALTEK_USB_DEVICE(vend, prod) \ | |
17734 | + USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC) | |
17735 | + | |
17736 | +struct tally_counter { | |
17737 | + __le64 tx_packets; | |
17738 | + __le64 rx_packets; | |
17739 | + __le64 tx_errors; | |
17740 | + __le32 rx_errors; | |
17741 | + __le16 rx_missed; | |
17742 | + __le16 align_errors; | |
17743 | + __le32 tx_one_collision; | |
17744 | + __le32 tx_multi_collision; | |
17745 | + __le64 rx_unicast; | |
17746 | + __le64 rx_broadcast; | |
17747 | + __le32 rx_multicast; | |
17748 | + __le16 tx_aborted; | |
17749 | + __le16 tx_underun; | |
17750 | +}; | |
17751 | + | |
17752 | +struct rx_desc { | |
17753 | + __le32 opts1; | |
17754 | +#define RX_LEN_MASK 0x7fff | |
17755 | + | |
17756 | + __le32 opts2; | |
17757 | +#define RD_UDP_CS (1 << 23) | |
17758 | +#define RD_TCP_CS (1 << 22) | |
17759 | +#define RD_IPV6_CS (1 << 20) | |
17760 | +#define RD_IPV4_CS (1 << 19) | |
17761 | + | |
17762 | + __le32 opts3; | |
17763 | +#define IPF (1 << 23) /* IP checksum fail */ | |
17764 | +#define UDPF (1 << 22) /* UDP checksum fail */ | |
17765 | +#define TCPF (1 << 21) /* TCP checksum fail */ | |
17766 | +#define RX_VLAN_TAG (1 << 16) | |
17767 | + | |
17768 | + __le32 opts4; | |
17769 | + __le32 opts5; | |
17770 | + __le32 opts6; | |
17771 | +}; | |
17772 | + | |
17773 | +struct tx_desc { | |
17774 | + __le32 opts1; | |
17775 | +#define TX_FS (1 << 31) /* First segment of a packet */ | |
17776 | +#define TX_LS (1 << 30) /* Final segment of a packet */ | |
17777 | +#define GTSENDV4 (1 << 28) | |
17778 | +#define GTSENDV6 (1 << 27) | |
17779 | +#define GTTCPHO_SHIFT 18 | |
17780 | +#define GTTCPHO_MAX 0x7fU | |
17781 | +#define TX_LEN_MAX 0x3ffffU | |
17782 | + | |
17783 | + __le32 opts2; | |
17784 | +#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ | |
17785 | +#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ | |
17786 | +#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ | |
17787 | +#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ | |
17788 | +#define MSS_SHIFT 17 | |
17789 | +#define MSS_MAX 0x7ffU | |
17790 | +#define TCPHO_SHIFT 17 | |
17791 | +#define TCPHO_MAX 0x7ffU | |
17792 | +#define TX_VLAN_TAG (1 << 16) | |
17793 | +}; | |
17794 | + | |
17795 | +struct r8152; | |
17796 | + | |
17797 | +struct rx_agg { | |
17798 | + struct list_head list; | |
17799 | + struct urb *urb; | |
17800 | + struct r8152 *context; | |
17801 | + void *buffer; | |
17802 | + void *head; | |
17803 | +}; | |
17804 | + | |
17805 | +struct tx_agg { | |
17806 | + struct list_head list; | |
17807 | + struct urb *urb; | |
17808 | + struct r8152 *context; | |
17809 | + void *buffer; | |
17810 | + void *head; | |
17811 | + u32 skb_num; | |
17812 | + u32 skb_len; | |
17813 | +}; | |
17814 | + | |
17815 | +struct r8152 { | |
17816 | + unsigned long flags; | |
17817 | + struct usb_device *udev; | |
17818 | + struct tasklet_struct tl; | |
17819 | + struct usb_interface *intf; | |
17820 | + struct net_device *netdev; | |
17821 | + struct urb *intr_urb; | |
17822 | + struct tx_agg tx_info[RTL8152_MAX_TX]; | |
17823 | + struct rx_agg rx_info[RTL8152_MAX_RX]; | |
17824 | + struct list_head rx_done, tx_free; | |
17825 | + struct sk_buff_head tx_queue; | |
17826 | + spinlock_t rx_lock, tx_lock; | |
17827 | + struct delayed_work schedule; | |
17828 | + struct mii_if_info mii; | |
17829 | + struct mutex control; /* use for hw setting */ | |
17830 | + | |
17831 | + struct rtl_ops { | |
17832 | + void (*init)(struct r8152 *); | |
17833 | + int (*enable)(struct r8152 *); | |
17834 | + void (*disable)(struct r8152 *); | |
17835 | + void (*up)(struct r8152 *); | |
17836 | + void (*down)(struct r8152 *); | |
17837 | + void (*unload)(struct r8152 *); | |
17838 | + int (*eee_get)(struct r8152 *, struct ethtool_eee *); | |
17839 | + int (*eee_set)(struct r8152 *, struct ethtool_eee *); | |
17840 | + } __no_const rtl_ops; | |
17841 | + | |
17842 | + int intr_interval; | |
17843 | + u32 saved_wolopts; | |
17844 | + u32 msg_enable; | |
17845 | + u32 tx_qlen; | |
17846 | + u16 ocp_base; | |
17847 | + u8 *intr_buff; | |
17848 | + u8 version; | |
17849 | + u8 speed; | |
17850 | +}; | |
17851 | + | |
17852 | +enum rtl_version { | |
17853 | + RTL_VER_UNKNOWN = 0, | |
17854 | + RTL_VER_01, | |
17855 | + RTL_VER_02, | |
17856 | + RTL_VER_03, | |
17857 | + RTL_VER_04, | |
17858 | + RTL_VER_05, | |
17859 | + RTL_VER_MAX | |
17860 | +}; | |
17861 | + | |
17862 | +enum tx_csum_stat { | |
17863 | + TX_CSUM_SUCCESS = 0, | |
17864 | + TX_CSUM_TSO, | |
17865 | + TX_CSUM_NONE | |
17866 | +}; | |
17867 | + | |
17868 | +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). | |
17869 | + * The RTL chips use a 64 element hash table based on the Ethernet CRC. | |
17870 | + */ | |
17871 | +static const int multicast_filter_limit = 32; | |
17872 | +static unsigned int agg_buf_sz = 16384; | |
17873 | + | |
17874 | +#define RTL_LIMITED_TSO_SIZE (agg_buf_sz - sizeof(struct tx_desc) - \ | |
17875 | + VLAN_ETH_HLEN - VLAN_HLEN) | |
17876 | + | |
17877 | +static | |
17878 | +int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) | |
17879 | +{ | |
17880 | + int ret; | |
17881 | + void *tmp; | |
17882 | + | |
17883 | + tmp = kmalloc(size, GFP_KERNEL); | |
17884 | + if (!tmp) | |
17885 | + return -ENOMEM; | |
17886 | + | |
17887 | + ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), | |
17888 | + RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, | |
17889 | + value, index, tmp, size, 500); | |
17890 | + | |
17891 | + memcpy(data, tmp, size); | |
17892 | + kfree(tmp); | |
17893 | + | |
17894 | + return ret; | |
17895 | +} | |
17896 | + | |
17897 | +static | |
17898 | +int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) | |
17899 | +{ | |
17900 | + int ret; | |
17901 | + void *tmp; | |
17902 | + | |
17903 | + tmp = kmemdup(data, size, GFP_KERNEL); | |
17904 | + if (!tmp) | |
17905 | + return -ENOMEM; | |
17906 | + | |
17907 | + ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), | |
17908 | + RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, | |
17909 | + value, index, tmp, size, 500); | |
17910 | + | |
17911 | + kfree(tmp); | |
17912 | + | |
17913 | + return ret; | |
17914 | +} | |
17915 | + | |
17916 | +static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, | |
17917 | + void *data, u16 type) | |
17918 | +{ | |
17919 | + u16 limit = 64; | |
17920 | + int ret = 0; | |
17921 | + | |
17922 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
17923 | + return -ENODEV; | |
17924 | + | |
17925 | + /* both size and indix must be 4 bytes align */ | |
17926 | + if ((size & 3) || !size || (index & 3) || !data) | |
17927 | + return -EPERM; | |
17928 | + | |
17929 | + if ((u32)index + (u32)size > 0xffff) | |
17930 | + return -EPERM; | |
17931 | + | |
17932 | + while (size) { | |
17933 | + if (size > limit) { | |
17934 | + ret = get_registers(tp, index, type, limit, data); | |
17935 | + if (ret < 0) | |
17936 | + break; | |
17937 | + | |
17938 | + index += limit; | |
17939 | + data += limit; | |
17940 | + size -= limit; | |
17941 | + } else { | |
17942 | + ret = get_registers(tp, index, type, size, data); | |
17943 | + if (ret < 0) | |
17944 | + break; | |
17945 | + | |
17946 | + index += size; | |
17947 | + data += size; | |
17948 | + size = 0; | |
17949 | + break; | |
17950 | + } | |
17951 | + } | |
17952 | + | |
17953 | + return ret; | |
17954 | +} | |
17955 | + | |
17956 | +static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen, | |
17957 | + u16 size, void *data, u16 type) | |
17958 | +{ | |
17959 | + int ret; | |
17960 | + u16 byteen_start, byteen_end, byen; | |
17961 | + u16 limit = 512; | |
17962 | + | |
17963 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
17964 | + return -ENODEV; | |
17965 | + | |
17966 | + /* both size and indix must be 4 bytes align */ | |
17967 | + if ((size & 3) || !size || (index & 3) || !data) | |
17968 | + return -EPERM; | |
17969 | + | |
17970 | + if ((u32)index + (u32)size > 0xffff) | |
17971 | + return -EPERM; | |
17972 | + | |
17973 | + byteen_start = byteen & BYTE_EN_START_MASK; | |
17974 | + byteen_end = byteen & BYTE_EN_END_MASK; | |
17975 | + | |
17976 | + byen = byteen_start | (byteen_start << 4); | |
17977 | + ret = set_registers(tp, index, type | byen, 4, data); | |
17978 | + if (ret < 0) | |
17979 | + goto error1; | |
17980 | + | |
17981 | + index += 4; | |
17982 | + data += 4; | |
17983 | + size -= 4; | |
17984 | + | |
17985 | + if (size) { | |
17986 | + size -= 4; | |
17987 | + | |
17988 | + while (size) { | |
17989 | + if (size > limit) { | |
17990 | + ret = set_registers(tp, index, | |
17991 | + type | BYTE_EN_DWORD, | |
17992 | + limit, data); | |
17993 | + if (ret < 0) | |
17994 | + goto error1; | |
17995 | + | |
17996 | + index += limit; | |
17997 | + data += limit; | |
17998 | + size -= limit; | |
17999 | + } else { | |
18000 | + ret = set_registers(tp, index, | |
18001 | + type | BYTE_EN_DWORD, | |
18002 | + size, data); | |
18003 | + if (ret < 0) | |
18004 | + goto error1; | |
18005 | + | |
18006 | + index += size; | |
18007 | + data += size; | |
18008 | + size = 0; | |
18009 | + break; | |
18010 | + } | |
18011 | + } | |
18012 | + | |
18013 | + byen = byteen_end | (byteen_end >> 4); | |
18014 | + ret = set_registers(tp, index, type | byen, 4, data); | |
18015 | + if (ret < 0) | |
18016 | + goto error1; | |
18017 | + } | |
18018 | + | |
18019 | +error1: | |
18020 | + return ret; | |
18021 | +} | |
18022 | + | |
18023 | +static inline | |
18024 | +int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) | |
18025 | +{ | |
18026 | + return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA); | |
18027 | +} | |
18028 | + | |
18029 | +static inline | |
18030 | +int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) | |
18031 | +{ | |
18032 | + return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA); | |
18033 | +} | |
18034 | + | |
18035 | +static inline | |
18036 | +int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data) | |
18037 | +{ | |
18038 | + return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB); | |
18039 | +} | |
18040 | + | |
18041 | +static inline | |
18042 | +int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) | |
18043 | +{ | |
18044 | + return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB); | |
18045 | +} | |
18046 | + | |
18047 | +static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index) | |
18048 | +{ | |
18049 | + __le32 data; | |
18050 | + | |
18051 | + generic_ocp_read(tp, index, sizeof(data), &data, type); | |
18052 | + | |
18053 | + return __le32_to_cpu(data); | |
18054 | +} | |
18055 | + | |
18056 | +static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data) | |
18057 | +{ | |
18058 | + __le32 tmp = __cpu_to_le32(data); | |
18059 | + | |
18060 | + generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type); | |
18061 | +} | |
18062 | + | |
18063 | +static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) | |
18064 | +{ | |
18065 | + u32 data; | |
18066 | + __le32 tmp; | |
18067 | + u8 shift = index & 2; | |
18068 | + | |
18069 | + index &= ~3; | |
18070 | + | |
18071 | + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); | |
18072 | + | |
18073 | + data = __le32_to_cpu(tmp); | |
18074 | + data >>= (shift * 8); | |
18075 | + data &= 0xffff; | |
18076 | + | |
18077 | + return (u16)data; | |
18078 | +} | |
18079 | + | |
18080 | +static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) | |
18081 | +{ | |
18082 | + u32 mask = 0xffff; | |
18083 | + __le32 tmp; | |
18084 | + u16 byen = BYTE_EN_WORD; | |
18085 | + u8 shift = index & 2; | |
18086 | + | |
18087 | + data &= mask; | |
18088 | + | |
18089 | + if (index & 2) { | |
18090 | + byen <<= shift; | |
18091 | + mask <<= (shift * 8); | |
18092 | + data <<= (shift * 8); | |
18093 | + index &= ~3; | |
18094 | + } | |
18095 | + | |
18096 | + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); | |
18097 | + | |
18098 | + data |= __le32_to_cpu(tmp) & ~mask; | |
18099 | + tmp = __cpu_to_le32(data); | |
18100 | + | |
18101 | + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); | |
18102 | +} | |
18103 | + | |
18104 | +static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) | |
18105 | +{ | |
18106 | + u32 data; | |
18107 | + __le32 tmp; | |
18108 | + u8 shift = index & 3; | |
18109 | + | |
18110 | + index &= ~3; | |
18111 | + | |
18112 | + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); | |
18113 | + | |
18114 | + data = __le32_to_cpu(tmp); | |
18115 | + data >>= (shift * 8); | |
18116 | + data &= 0xff; | |
18117 | + | |
18118 | + return (u8)data; | |
18119 | +} | |
18120 | + | |
18121 | +static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) | |
18122 | +{ | |
18123 | + u32 mask = 0xff; | |
18124 | + __le32 tmp; | |
18125 | + u16 byen = BYTE_EN_BYTE; | |
18126 | + u8 shift = index & 3; | |
18127 | + | |
18128 | + data &= mask; | |
18129 | + | |
18130 | + if (index & 3) { | |
18131 | + byen <<= shift; | |
18132 | + mask <<= (shift * 8); | |
18133 | + data <<= (shift * 8); | |
18134 | + index &= ~3; | |
18135 | + } | |
18136 | + | |
18137 | + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); | |
18138 | + | |
18139 | + data |= __le32_to_cpu(tmp) & ~mask; | |
18140 | + tmp = __cpu_to_le32(data); | |
18141 | + | |
18142 | + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); | |
18143 | +} | |
18144 | + | |
18145 | +static u16 ocp_reg_read(struct r8152 *tp, u16 addr) | |
18146 | +{ | |
18147 | + u16 ocp_base, ocp_index; | |
18148 | + | |
18149 | + ocp_base = addr & 0xf000; | |
18150 | + if (ocp_base != tp->ocp_base) { | |
18151 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); | |
18152 | + tp->ocp_base = ocp_base; | |
18153 | + } | |
18154 | + | |
18155 | + ocp_index = (addr & 0x0fff) | 0xb000; | |
18156 | + return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index); | |
18157 | +} | |
18158 | + | |
18159 | +static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) | |
18160 | +{ | |
18161 | + u16 ocp_base, ocp_index; | |
18162 | + | |
18163 | + ocp_base = addr & 0xf000; | |
18164 | + if (ocp_base != tp->ocp_base) { | |
18165 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); | |
18166 | + tp->ocp_base = ocp_base; | |
18167 | + } | |
18168 | + | |
18169 | + ocp_index = (addr & 0x0fff) | 0xb000; | |
18170 | + ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); | |
18171 | +} | |
18172 | + | |
18173 | +static inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) | |
18174 | +{ | |
18175 | + ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value); | |
18176 | +} | |
18177 | + | |
18178 | +static inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr) | |
18179 | +{ | |
18180 | + return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2); | |
18181 | +} | |
18182 | + | |
18183 | +static void sram_write(struct r8152 *tp, u16 addr, u16 data) | |
18184 | +{ | |
18185 | + ocp_reg_write(tp, OCP_SRAM_ADDR, addr); | |
18186 | + ocp_reg_write(tp, OCP_SRAM_DATA, data); | |
18187 | +} | |
18188 | + | |
18189 | +static u16 sram_read(struct r8152 *tp, u16 addr) | |
18190 | +{ | |
18191 | + ocp_reg_write(tp, OCP_SRAM_ADDR, addr); | |
18192 | + return ocp_reg_read(tp, OCP_SRAM_DATA); | |
18193 | +} | |
18194 | + | |
18195 | +static int read_mii_word(struct net_device *netdev, int phy_id, int reg) | |
18196 | +{ | |
18197 | + struct r8152 *tp = netdev_priv(netdev); | |
18198 | + int ret; | |
18199 | + | |
18200 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
18201 | + return -ENODEV; | |
18202 | + | |
18203 | + if (phy_id != R8152_PHY_ID) | |
18204 | + return -EINVAL; | |
18205 | + | |
18206 | + ret = r8152_mdio_read(tp, reg); | |
18207 | + | |
18208 | + return ret; | |
18209 | +} | |
18210 | + | |
18211 | +static | |
18212 | +void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) | |
18213 | +{ | |
18214 | + struct r8152 *tp = netdev_priv(netdev); | |
18215 | + | |
18216 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
18217 | + return; | |
18218 | + | |
18219 | + if (phy_id != R8152_PHY_ID) | |
18220 | + return; | |
18221 | + | |
18222 | + r8152_mdio_write(tp, reg, val); | |
18223 | +} | |
18224 | + | |
18225 | +static int | |
18226 | +r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); | |
18227 | + | |
18228 | +static int rtl8152_set_mac_address(struct net_device *netdev, void *p) | |
18229 | +{ | |
18230 | + struct r8152 *tp = netdev_priv(netdev); | |
18231 | + struct sockaddr *addr = p; | |
18232 | + int ret = -EADDRNOTAVAIL; | |
18233 | + | |
18234 | + if (!is_valid_ether_addr(addr->sa_data)) | |
18235 | + goto out1; | |
18236 | + | |
18237 | + ret = usb_autopm_get_interface(tp->intf); | |
18238 | + if (ret < 0) | |
18239 | + goto out1; | |
18240 | + | |
18241 | + mutex_lock(&tp->control); | |
18242 | + | |
18243 | + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | |
18244 | + | |
18245 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); | |
18246 | + pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data); | |
18247 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); | |
18248 | + | |
18249 | + mutex_unlock(&tp->control); | |
18250 | + | |
18251 | + usb_autopm_put_interface(tp->intf); | |
18252 | +out1: | |
18253 | + return ret; | |
18254 | +} | |
18255 | + | |
18256 | +static int set_ethernet_addr(struct r8152 *tp) | |
18257 | +{ | |
18258 | + struct net_device *dev = tp->netdev; | |
18259 | + struct sockaddr sa; | |
18260 | + int ret; | |
18261 | + | |
18262 | + if (tp->version == RTL_VER_01) | |
18263 | + ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data); | |
18264 | + else | |
18265 | + ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data); | |
18266 | + | |
18267 | + if (ret < 0) { | |
18268 | + netif_err(tp, probe, dev, "Get ether addr fail\n"); | |
18269 | + } else if (!is_valid_ether_addr(sa.sa_data)) { | |
18270 | + netif_err(tp, probe, dev, "Invalid ether addr %pM\n", | |
18271 | + sa.sa_data); | |
18272 | + eth_hw_addr_random(dev); | |
18273 | + ether_addr_copy(sa.sa_data, dev->dev_addr); | |
18274 | + ret = rtl8152_set_mac_address(dev, &sa); | |
18275 | + netif_info(tp, probe, dev, "Random ether addr %pM\n", | |
18276 | + sa.sa_data); | |
18277 | + } else { | |
18278 | + if (tp->version == RTL_VER_01) | |
18279 | + ether_addr_copy(dev->dev_addr, sa.sa_data); | |
18280 | + else | |
18281 | + ret = rtl8152_set_mac_address(dev, &sa); | |
18282 | + } | |
18283 | + | |
18284 | + return ret; | |
18285 | +} | |
18286 | + | |
18287 | +static void read_bulk_callback(struct urb *urb) | |
18288 | +{ | |
18289 | + struct net_device *netdev; | |
18290 | + int status = urb->status; | |
18291 | + struct rx_agg *agg; | |
18292 | + struct r8152 *tp; | |
18293 | + int result; | |
18294 | + | |
18295 | + agg = urb->context; | |
18296 | + if (!agg) | |
18297 | + return; | |
18298 | + | |
18299 | + tp = agg->context; | |
18300 | + if (!tp) | |
18301 | + return; | |
18302 | + | |
18303 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
18304 | + return; | |
18305 | + | |
18306 | + if (!test_bit(WORK_ENABLE, &tp->flags)) | |
18307 | + return; | |
18308 | + | |
18309 | + netdev = tp->netdev; | |
18310 | + | |
18311 | + /* When link down, the driver would cancel all bulks. */ | |
18312 | + /* This avoid the re-submitting bulk */ | |
18313 | + if (!netif_carrier_ok(netdev)) | |
18314 | + return; | |
18315 | + | |
18316 | + usb_mark_last_busy(tp->udev); | |
18317 | + | |
18318 | + switch (status) { | |
18319 | + case 0: | |
18320 | + if (urb->actual_length < ETH_ZLEN) | |
18321 | + break; | |
18322 | + | |
18323 | + spin_lock(&tp->rx_lock); | |
18324 | + list_add_tail(&agg->list, &tp->rx_done); | |
18325 | + spin_unlock(&tp->rx_lock); | |
18326 | + tasklet_schedule(&tp->tl); | |
18327 | + return; | |
18328 | + case -ESHUTDOWN: | |
18329 | + set_bit(RTL8152_UNPLUG, &tp->flags); | |
18330 | + netif_device_detach(tp->netdev); | |
18331 | + return; | |
18332 | + case -ENOENT: | |
18333 | + return; /* the urb is in unlink state */ | |
18334 | + case -ETIME: | |
18335 | + if (net_ratelimit()) | |
18336 | + netdev_warn(netdev, "maybe reset is needed?\n"); | |
18337 | + break; | |
18338 | + default: | |
18339 | + if (net_ratelimit()) | |
18340 | + netdev_warn(netdev, "Rx status %d\n", status); | |
18341 | + break; | |
18342 | + } | |
18343 | + | |
18344 | + result = r8152_submit_rx(tp, agg, GFP_ATOMIC); | |
18345 | + if (result == -ENODEV) { | |
18346 | + netif_device_detach(tp->netdev); | |
18347 | + } else if (result) { | |
18348 | + spin_lock(&tp->rx_lock); | |
18349 | + list_add_tail(&agg->list, &tp->rx_done); | |
18350 | + spin_unlock(&tp->rx_lock); | |
18351 | + tasklet_schedule(&tp->tl); | |
18352 | + } | |
18353 | +} | |
18354 | + | |
18355 | +static void write_bulk_callback(struct urb *urb) | |
18356 | +{ | |
18357 | + struct net_device_stats *stats; | |
18358 | + struct net_device *netdev; | |
18359 | + struct tx_agg *agg; | |
18360 | + struct r8152 *tp; | |
18361 | + int status = urb->status; | |
18362 | + | |
18363 | + agg = urb->context; | |
18364 | + if (!agg) | |
18365 | + return; | |
18366 | + | |
18367 | + tp = agg->context; | |
18368 | + if (!tp) | |
18369 | + return; | |
18370 | + | |
18371 | + netdev = tp->netdev; | |
18372 | + stats = &netdev->stats; | |
18373 | + if (status) { | |
18374 | + if (net_ratelimit()) | |
18375 | + netdev_warn(netdev, "Tx status %d\n", status); | |
18376 | + stats->tx_errors += agg->skb_num; | |
18377 | + } else { | |
18378 | + stats->tx_packets += agg->skb_num; | |
18379 | + stats->tx_bytes += agg->skb_len; | |
18380 | + } | |
18381 | + | |
18382 | + spin_lock(&tp->tx_lock); | |
18383 | + list_add_tail(&agg->list, &tp->tx_free); | |
18384 | + spin_unlock(&tp->tx_lock); | |
18385 | + | |
18386 | + usb_autopm_put_interface_async(tp->intf); | |
18387 | + | |
18388 | + if (!netif_carrier_ok(netdev)) | |
18389 | + return; | |
18390 | + | |
18391 | + if (!test_bit(WORK_ENABLE, &tp->flags)) | |
18392 | + return; | |
18393 | + | |
18394 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
18395 | + return; | |
18396 | + | |
18397 | + if (!skb_queue_empty(&tp->tx_queue)) | |
18398 | + tasklet_schedule(&tp->tl); | |
18399 | +} | |
18400 | + | |
18401 | +static void intr_callback(struct urb *urb) | |
18402 | +{ | |
18403 | + struct r8152 *tp; | |
18404 | + __le16 *d; | |
18405 | + int status = urb->status; | |
18406 | + int res; | |
18407 | + | |
18408 | + tp = urb->context; | |
18409 | + if (!tp) | |
18410 | + return; | |
18411 | + | |
18412 | + if (!test_bit(WORK_ENABLE, &tp->flags)) | |
18413 | + return; | |
18414 | + | |
18415 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
18416 | + return; | |
18417 | + | |
18418 | + switch (status) { | |
18419 | + case 0: /* success */ | |
18420 | + break; | |
18421 | + case -ECONNRESET: /* unlink */ | |
18422 | + case -ESHUTDOWN: | |
18423 | + netif_device_detach(tp->netdev); | |
18424 | + case -ENOENT: | |
18425 | + case -EPROTO: | |
18426 | + netif_info(tp, intr, tp->netdev, | |
18427 | + "Stop submitting intr, status %d\n", status); | |
18428 | + return; | |
18429 | + case -EOVERFLOW: | |
18430 | + netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n"); | |
18431 | + goto resubmit; | |
18432 | + /* -EPIPE: should clear the halt */ | |
18433 | + default: | |
18434 | + netif_info(tp, intr, tp->netdev, "intr status %d\n", status); | |
18435 | + goto resubmit; | |
18436 | + } | |
18437 | + | |
18438 | + d = urb->transfer_buffer; | |
18439 | + if (INTR_LINK & __le16_to_cpu(d[0])) { | |
18440 | + if (!(tp->speed & LINK_STATUS)) { | |
18441 | + set_bit(RTL8152_LINK_CHG, &tp->flags); | |
18442 | + schedule_delayed_work(&tp->schedule, 0); | |
18443 | + } | |
18444 | + } else { | |
18445 | + if (tp->speed & LINK_STATUS) { | |
18446 | + set_bit(RTL8152_LINK_CHG, &tp->flags); | |
18447 | + schedule_delayed_work(&tp->schedule, 0); | |
18448 | + } | |
18449 | + } | |
18450 | + | |
18451 | +resubmit: | |
18452 | + res = usb_submit_urb(urb, GFP_ATOMIC); | |
18453 | + if (res == -ENODEV) | |
18454 | + netif_device_detach(tp->netdev); | |
18455 | + else if (res) | |
18456 | + netif_err(tp, intr, tp->netdev, | |
18457 | + "can't resubmit intr, status %d\n", res); | |
18458 | +} | |
18459 | + | |
18460 | +static inline void *rx_agg_align(void *data) | |
18461 | +{ | |
18462 | + return (void *)ALIGN((uintptr_t)data, RX_ALIGN); | |
18463 | +} | |
18464 | + | |
18465 | +static inline void *tx_agg_align(void *data) | |
18466 | +{ | |
18467 | + return (void *)ALIGN((uintptr_t)data, TX_ALIGN); | |
18468 | +} | |
18469 | + | |
18470 | +static void free_all_mem(struct r8152 *tp) | |
18471 | +{ | |
18472 | + int i; | |
18473 | + | |
18474 | + for (i = 0; i < RTL8152_MAX_RX; i++) { | |
18475 | + usb_free_urb(tp->rx_info[i].urb); | |
18476 | + tp->rx_info[i].urb = NULL; | |
18477 | + | |
18478 | + kfree(tp->rx_info[i].buffer); | |
18479 | + tp->rx_info[i].buffer = NULL; | |
18480 | + tp->rx_info[i].head = NULL; | |
18481 | + } | |
18482 | + | |
18483 | + for (i = 0; i < RTL8152_MAX_TX; i++) { | |
18484 | + usb_free_urb(tp->tx_info[i].urb); | |
18485 | + tp->tx_info[i].urb = NULL; | |
18486 | + | |
18487 | + kfree(tp->tx_info[i].buffer); | |
18488 | + tp->tx_info[i].buffer = NULL; | |
18489 | + tp->tx_info[i].head = NULL; | |
18490 | + } | |
18491 | + | |
18492 | + usb_free_urb(tp->intr_urb); | |
18493 | + tp->intr_urb = NULL; | |
18494 | + | |
18495 | + kfree(tp->intr_buff); | |
18496 | + tp->intr_buff = NULL; | |
18497 | +} | |
18498 | + | |
18499 | +static int alloc_all_mem(struct r8152 *tp) | |
18500 | +{ | |
18501 | + struct net_device *netdev = tp->netdev; | |
18502 | + struct usb_interface *intf = tp->intf; | |
18503 | + struct usb_host_interface *alt = intf->cur_altsetting; | |
18504 | + struct usb_host_endpoint *ep_intr = alt->endpoint + 2; | |
18505 | + struct urb *urb; | |
18506 | + int node, i; | |
18507 | + u8 *buf; | |
18508 | + | |
18509 | + node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1; | |
18510 | + | |
18511 | + spin_lock_init(&tp->rx_lock); | |
18512 | + spin_lock_init(&tp->tx_lock); | |
18513 | + INIT_LIST_HEAD(&tp->rx_done); | |
18514 | + INIT_LIST_HEAD(&tp->tx_free); | |
18515 | + skb_queue_head_init(&tp->tx_queue); | |
18516 | + | |
18517 | + for (i = 0; i < RTL8152_MAX_RX; i++) { | |
18518 | + buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); | |
18519 | + if (!buf) | |
18520 | + goto err1; | |
18521 | + | |
18522 | + if (buf != rx_agg_align(buf)) { | |
18523 | + kfree(buf); | |
18524 | + buf = kmalloc_node(agg_buf_sz + RX_ALIGN, GFP_KERNEL, | |
18525 | + node); | |
18526 | + if (!buf) | |
18527 | + goto err1; | |
18528 | + } | |
18529 | + | |
18530 | + urb = usb_alloc_urb(0, GFP_KERNEL); | |
18531 | + if (!urb) { | |
18532 | + kfree(buf); | |
18533 | + goto err1; | |
18534 | + } | |
18535 | + | |
18536 | + INIT_LIST_HEAD(&tp->rx_info[i].list); | |
18537 | + tp->rx_info[i].context = tp; | |
18538 | + tp->rx_info[i].urb = urb; | |
18539 | + tp->rx_info[i].buffer = buf; | |
18540 | + tp->rx_info[i].head = rx_agg_align(buf); | |
18541 | + } | |
18542 | + | |
18543 | + for (i = 0; i < RTL8152_MAX_TX; i++) { | |
18544 | + buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); | |
18545 | + if (!buf) | |
18546 | + goto err1; | |
18547 | + | |
18548 | + if (buf != tx_agg_align(buf)) { | |
18549 | + kfree(buf); | |
18550 | + buf = kmalloc_node(agg_buf_sz + TX_ALIGN, GFP_KERNEL, | |
18551 | + node); | |
18552 | + if (!buf) | |
18553 | + goto err1; | |
18554 | + } | |
18555 | + | |
18556 | + urb = usb_alloc_urb(0, GFP_KERNEL); | |
18557 | + if (!urb) { | |
18558 | + kfree(buf); | |
18559 | + goto err1; | |
18560 | + } | |
18561 | + | |
18562 | + INIT_LIST_HEAD(&tp->tx_info[i].list); | |
18563 | + tp->tx_info[i].context = tp; | |
18564 | + tp->tx_info[i].urb = urb; | |
18565 | + tp->tx_info[i].buffer = buf; | |
18566 | + tp->tx_info[i].head = tx_agg_align(buf); | |
18567 | + | |
18568 | + list_add_tail(&tp->tx_info[i].list, &tp->tx_free); | |
18569 | + } | |
18570 | + | |
18571 | + tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | |
18572 | + if (!tp->intr_urb) | |
18573 | + goto err1; | |
18574 | + | |
18575 | + tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); | |
18576 | + if (!tp->intr_buff) | |
18577 | + goto err1; | |
18578 | + | |
18579 | + tp->intr_interval = (int)ep_intr->desc.bInterval; | |
18580 | + usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3), | |
18581 | + tp->intr_buff, INTBUFSIZE, intr_callback, | |
18582 | + tp, tp->intr_interval); | |
18583 | + | |
18584 | + return 0; | |
18585 | + | |
18586 | +err1: | |
18587 | + free_all_mem(tp); | |
18588 | + return -ENOMEM; | |
18589 | +} | |
18590 | + | |
18591 | +static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) | |
18592 | +{ | |
18593 | + struct tx_agg *agg = NULL; | |
18594 | + unsigned long flags; | |
18595 | + | |
18596 | + if (list_empty(&tp->tx_free)) | |
18597 | + return NULL; | |
18598 | + | |
18599 | + spin_lock_irqsave(&tp->tx_lock, flags); | |
18600 | + if (!list_empty(&tp->tx_free)) { | |
18601 | + struct list_head *cursor; | |
18602 | + | |
18603 | + cursor = tp->tx_free.next; | |
18604 | + list_del_init(cursor); | |
18605 | + agg = list_entry(cursor, struct tx_agg, list); | |
18606 | + } | |
18607 | + spin_unlock_irqrestore(&tp->tx_lock, flags); | |
18608 | + | |
18609 | + return agg; | |
18610 | +} | |
18611 | + | |
18612 | +static inline __be16 get_protocol(struct sk_buff *skb) | |
18613 | +{ | |
18614 | + __be16 protocol; | |
18615 | + | |
18616 | + if (skb->protocol == htons(ETH_P_8021Q)) | |
18617 | + protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; | |
18618 | + else | |
18619 | + protocol = skb->protocol; | |
18620 | + | |
18621 | + return protocol; | |
18622 | +} | |
18623 | + | |
18624 | +/* r8152_csum_workaround() | |
18625 | + * The hw limites the value the transport offset. When the offset is out of the | |
18626 | + * range, calculate the checksum by sw. | |
18627 | + */ | |
18628 | +static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, | |
18629 | + struct sk_buff_head *list) | |
18630 | +{ | |
18631 | + if (skb_shinfo(skb)->gso_size) { | |
18632 | + netdev_features_t features = tp->netdev->features; | |
18633 | + struct sk_buff_head seg_list; | |
18634 | + struct sk_buff *segs, *nskb; | |
18635 | + | |
18636 | + features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); | |
18637 | + segs = skb_gso_segment(skb, features); | |
18638 | + if (IS_ERR(segs) || !segs) | |
18639 | + goto drop; | |
18640 | + | |
18641 | + __skb_queue_head_init(&seg_list); | |
18642 | + | |
18643 | + do { | |
18644 | + nskb = segs; | |
18645 | + segs = segs->next; | |
18646 | + nskb->next = NULL; | |
18647 | + __skb_queue_tail(&seg_list, nskb); | |
18648 | + } while (segs); | |
18649 | + | |
18650 | + skb_queue_splice(&seg_list, list); | |
18651 | + dev_kfree_skb(skb); | |
18652 | + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | |
18653 | + if (skb_checksum_help(skb) < 0) | |
18654 | + goto drop; | |
18655 | + | |
18656 | + __skb_queue_head(list, skb); | |
18657 | + } else { | |
18658 | + struct net_device_stats *stats; | |
18659 | + | |
18660 | +drop: | |
18661 | + stats = &tp->netdev->stats; | |
18662 | + stats->tx_dropped++; | |
18663 | + dev_kfree_skb(skb); | |
18664 | + } | |
18665 | +} | |
18666 | + | |
18667 | +/* msdn_giant_send_check() | |
18668 | + * According to the document of microsoft, the TCP Pseudo Header excludes the | |
18669 | + * packet length for IPv6 TCP large packets. | |
18670 | + */ | |
18671 | +static int msdn_giant_send_check(struct sk_buff *skb) | |
18672 | +{ | |
18673 | + const struct ipv6hdr *ipv6h; | |
18674 | + struct tcphdr *th; | |
18675 | + int ret; | |
18676 | + | |
18677 | + ret = skb_cow_head(skb, 0); | |
18678 | + if (ret) | |
18679 | + return ret; | |
18680 | + | |
18681 | + ipv6h = ipv6_hdr(skb); | |
18682 | + th = tcp_hdr(skb); | |
18683 | + | |
18684 | + th->check = 0; | |
18685 | + th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); | |
18686 | + | |
18687 | + return ret; | |
18688 | +} | |
18689 | + | |
18690 | +static inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb) | |
18691 | +{ | |
18692 | + if (vlan_tx_tag_present(skb)) { | |
18693 | + u32 opts2; | |
18694 | + | |
18695 | + opts2 = TX_VLAN_TAG | swab16(vlan_tx_tag_get(skb)); | |
18696 | + desc->opts2 |= cpu_to_le32(opts2); | |
18697 | + } | |
18698 | +} | |
18699 | + | |
18700 | +static inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb) | |
18701 | +{ | |
18702 | + u32 opts2 = le32_to_cpu(desc->opts2); | |
18703 | + | |
18704 | + if (opts2 & RX_VLAN_TAG) | |
18705 | + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), | |
18706 | + swab16(opts2 & 0xffff)); | |
18707 | +} | |
18708 | + | |
18709 | +static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, | |
18710 | + struct sk_buff *skb, u32 len, u32 transport_offset) | |
18711 | +{ | |
18712 | + u32 mss = skb_shinfo(skb)->gso_size; | |
18713 | + u32 opts1, opts2 = 0; | |
18714 | + int ret = TX_CSUM_SUCCESS; | |
18715 | + | |
18716 | + WARN_ON_ONCE(len > TX_LEN_MAX); | |
18717 | + | |
18718 | + opts1 = len | TX_FS | TX_LS; | |
18719 | + | |
18720 | + if (mss) { | |
18721 | + if (transport_offset > GTTCPHO_MAX) { | |
18722 | + netif_warn(tp, tx_err, tp->netdev, | |
18723 | + "Invalid transport offset 0x%x for TSO\n", | |
18724 | + transport_offset); | |
18725 | + ret = TX_CSUM_TSO; | |
18726 | + goto unavailable; | |
18727 | + } | |
18728 | + | |
18729 | + switch (get_protocol(skb)) { | |
18730 | + case htons(ETH_P_IP): | |
18731 | + opts1 |= GTSENDV4; | |
18732 | + break; | |
18733 | + | |
18734 | + case htons(ETH_P_IPV6): | |
18735 | + if (msdn_giant_send_check(skb)) { | |
18736 | + ret = TX_CSUM_TSO; | |
18737 | + goto unavailable; | |
18738 | + } | |
18739 | + opts1 |= GTSENDV6; | |
18740 | + break; | |
18741 | + | |
18742 | + default: | |
18743 | + WARN_ON_ONCE(1); | |
18744 | + break; | |
18745 | + } | |
18746 | + | |
18747 | + opts1 |= transport_offset << GTTCPHO_SHIFT; | |
18748 | + opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; | |
18749 | + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | |
18750 | + u8 ip_protocol; | |
18751 | + | |
18752 | + if (transport_offset > TCPHO_MAX) { | |
18753 | + netif_warn(tp, tx_err, tp->netdev, | |
18754 | + "Invalid transport offset 0x%x\n", | |
18755 | + transport_offset); | |
18756 | + ret = TX_CSUM_NONE; | |
18757 | + goto unavailable; | |
18758 | + } | |
18759 | + | |
18760 | + switch (get_protocol(skb)) { | |
18761 | + case htons(ETH_P_IP): | |
18762 | + opts2 |= IPV4_CS; | |
18763 | + ip_protocol = ip_hdr(skb)->protocol; | |
18764 | + break; | |
18765 | + | |
18766 | + case htons(ETH_P_IPV6): | |
18767 | + opts2 |= IPV6_CS; | |
18768 | + ip_protocol = ipv6_hdr(skb)->nexthdr; | |
18769 | + break; | |
18770 | + | |
18771 | + default: | |
18772 | + ip_protocol = IPPROTO_RAW; | |
18773 | + break; | |
18774 | + } | |
18775 | + | |
18776 | + if (ip_protocol == IPPROTO_TCP) | |
18777 | + opts2 |= TCP_CS; | |
18778 | + else if (ip_protocol == IPPROTO_UDP) | |
18779 | + opts2 |= UDP_CS; | |
18780 | + else | |
18781 | + WARN_ON_ONCE(1); | |
18782 | + | |
18783 | + opts2 |= transport_offset << TCPHO_SHIFT; | |
18784 | + } | |
18785 | + | |
18786 | + desc->opts2 = cpu_to_le32(opts2); | |
18787 | + desc->opts1 = cpu_to_le32(opts1); | |
18788 | + | |
18789 | +unavailable: | |
18790 | + return ret; | |
18791 | +} | |
18792 | + | |
18793 | +static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) | |
18794 | +{ | |
18795 | + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; | |
18796 | + int remain, ret; | |
18797 | + u8 *tx_data; | |
18798 | + | |
18799 | + __skb_queue_head_init(&skb_head); | |
18800 | + spin_lock(&tx_queue->lock); | |
18801 | + skb_queue_splice_init(tx_queue, &skb_head); | |
18802 | + spin_unlock(&tx_queue->lock); | |
18803 | + | |
18804 | + tx_data = agg->head; | |
18805 | + agg->skb_num = 0; | |
18806 | + agg->skb_len = 0; | |
18807 | + remain = agg_buf_sz; | |
18808 | + | |
18809 | + while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) { | |
18810 | + struct tx_desc *tx_desc; | |
18811 | + struct sk_buff *skb; | |
18812 | + unsigned int len; | |
18813 | + u32 offset; | |
18814 | + | |
18815 | + skb = __skb_dequeue(&skb_head); | |
18816 | + if (!skb) | |
18817 | + break; | |
18818 | + | |
18819 | + len = skb->len + sizeof(*tx_desc); | |
18820 | + | |
18821 | + if (len > remain) { | |
18822 | + __skb_queue_head(&skb_head, skb); | |
18823 | + break; | |
18824 | + } | |
18825 | + | |
18826 | + tx_data = tx_agg_align(tx_data); | |
18827 | + tx_desc = (struct tx_desc *)tx_data; | |
18828 | + | |
18829 | + offset = (u32)skb_transport_offset(skb); | |
18830 | + | |
18831 | + if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) { | |
18832 | + r8152_csum_workaround(tp, skb, &skb_head); | |
18833 | + continue; | |
18834 | + } | |
18835 | + | |
18836 | + rtl_tx_vlan_tag(tx_desc, skb); | |
18837 | + | |
18838 | + tx_data += sizeof(*tx_desc); | |
18839 | + | |
18840 | + len = skb->len; | |
18841 | + if (skb_copy_bits(skb, 0, tx_data, len) < 0) { | |
18842 | + struct net_device_stats *stats = &tp->netdev->stats; | |
18843 | + | |
18844 | + stats->tx_dropped++; | |
18845 | + dev_kfree_skb_any(skb); | |
18846 | + tx_data -= sizeof(*tx_desc); | |
18847 | + continue; | |
18848 | + } | |
18849 | + | |
18850 | + tx_data += len; | |
18851 | + agg->skb_len += len; | |
18852 | + agg->skb_num++; | |
18853 | + | |
18854 | + dev_kfree_skb_any(skb); | |
18855 | + | |
18856 | + remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); | |
18857 | + } | |
18858 | + | |
18859 | + if (!skb_queue_empty(&skb_head)) { | |
18860 | + spin_lock(&tx_queue->lock); | |
18861 | + skb_queue_splice(&skb_head, tx_queue); | |
18862 | + spin_unlock(&tx_queue->lock); | |
18863 | + } | |
18864 | + | |
18865 | + netif_tx_lock(tp->netdev); | |
18866 | + | |
18867 | + if (netif_queue_stopped(tp->netdev) && | |
18868 | + skb_queue_len(&tp->tx_queue) < tp->tx_qlen) | |
18869 | + netif_wake_queue(tp->netdev); | |
18870 | + | |
18871 | + netif_tx_unlock(tp->netdev); | |
18872 | + | |
18873 | + ret = usb_autopm_get_interface_async(tp->intf); | |
18874 | + if (ret < 0) | |
18875 | + goto out_tx_fill; | |
18876 | + | |
18877 | + usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), | |
18878 | + agg->head, (int)(tx_data - (u8 *)agg->head), | |
18879 | + (usb_complete_t)write_bulk_callback, agg); | |
18880 | + | |
18881 | + ret = usb_submit_urb(agg->urb, GFP_ATOMIC); | |
18882 | + if (ret < 0) | |
18883 | + usb_autopm_put_interface_async(tp->intf); | |
18884 | + | |
18885 | +out_tx_fill: | |
18886 | + return ret; | |
18887 | +} | |
18888 | + | |
18889 | +static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) | |
18890 | +{ | |
18891 | + u8 checksum = CHECKSUM_NONE; | |
18892 | + u32 opts2, opts3; | |
18893 | + | |
18894 | + if (tp->version == RTL_VER_01) | |
18895 | + goto return_result; | |
18896 | + | |
18897 | + opts2 = le32_to_cpu(rx_desc->opts2); | |
18898 | + opts3 = le32_to_cpu(rx_desc->opts3); | |
18899 | + | |
18900 | + if (opts2 & RD_IPV4_CS) { | |
18901 | + if (opts3 & IPF) | |
18902 | + checksum = CHECKSUM_NONE; | |
18903 | + else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF)) | |
18904 | + checksum = CHECKSUM_NONE; | |
18905 | + else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF)) | |
18906 | + checksum = CHECKSUM_NONE; | |
18907 | + else | |
18908 | + checksum = CHECKSUM_UNNECESSARY; | |
18909 | + } else if (RD_IPV6_CS) { | |
18910 | + if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) | |
18911 | + checksum = CHECKSUM_UNNECESSARY; | |
18912 | + else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) | |
18913 | + checksum = CHECKSUM_UNNECESSARY; | |
18914 | + } | |
18915 | + | |
18916 | +return_result: | |
18917 | + return checksum; | |
18918 | +} | |
18919 | + | |
18920 | +static void rx_bottom(struct r8152 *tp) | |
18921 | +{ | |
18922 | + unsigned long flags; | |
18923 | + struct list_head *cursor, *next, rx_queue; | |
18924 | + | |
18925 | + if (list_empty(&tp->rx_done)) | |
18926 | + return; | |
18927 | + | |
18928 | + INIT_LIST_HEAD(&rx_queue); | |
18929 | + spin_lock_irqsave(&tp->rx_lock, flags); | |
18930 | + list_splice_init(&tp->rx_done, &rx_queue); | |
18931 | + spin_unlock_irqrestore(&tp->rx_lock, flags); | |
18932 | + | |
18933 | + list_for_each_safe(cursor, next, &rx_queue) { | |
18934 | + struct rx_desc *rx_desc; | |
18935 | + struct rx_agg *agg; | |
18936 | + int len_used = 0; | |
18937 | + struct urb *urb; | |
18938 | + u8 *rx_data; | |
18939 | + int ret; | |
18940 | + | |
18941 | + list_del_init(cursor); | |
18942 | + | |
18943 | + agg = list_entry(cursor, struct rx_agg, list); | |
18944 | + urb = agg->urb; | |
18945 | + if (urb->actual_length < ETH_ZLEN) | |
18946 | + goto submit; | |
18947 | + | |
18948 | + rx_desc = agg->head; | |
18949 | + rx_data = agg->head; | |
18950 | + len_used += sizeof(struct rx_desc); | |
18951 | + | |
18952 | + while (urb->actual_length > len_used) { | |
18953 | + struct net_device *netdev = tp->netdev; | |
18954 | + struct net_device_stats *stats = &netdev->stats; | |
18955 | + unsigned int pkt_len; | |
18956 | + struct sk_buff *skb; | |
18957 | + | |
18958 | + pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK; | |
18959 | + if (pkt_len < ETH_ZLEN) | |
18960 | + break; | |
18961 | + | |
18962 | + len_used += pkt_len; | |
18963 | + if (urb->actual_length < len_used) | |
18964 | + break; | |
18965 | + | |
18966 | + pkt_len -= CRC_SIZE; | |
18967 | + rx_data += sizeof(struct rx_desc); | |
18968 | + | |
18969 | + skb = netdev_alloc_skb_ip_align(netdev, pkt_len); | |
18970 | + if (!skb) { | |
18971 | + stats->rx_dropped++; | |
18972 | + goto find_next_rx; | |
18973 | + } | |
18974 | + | |
18975 | + skb->ip_summed = r8152_rx_csum(tp, rx_desc); | |
18976 | + memcpy(skb->data, rx_data, pkt_len); | |
18977 | + skb_put(skb, pkt_len); | |
18978 | + skb->protocol = eth_type_trans(skb, netdev); | |
18979 | + rtl_rx_vlan_tag(rx_desc, skb); | |
18980 | + netif_receive_skb(skb); | |
18981 | + stats->rx_packets++; | |
18982 | + stats->rx_bytes += pkt_len; | |
18983 | + | |
18984 | +find_next_rx: | |
18985 | + rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); | |
18986 | + rx_desc = (struct rx_desc *)rx_data; | |
18987 | + len_used = (int)(rx_data - (u8 *)agg->head); | |
18988 | + len_used += sizeof(struct rx_desc); | |
18989 | + } | |
18990 | + | |
18991 | +submit: | |
18992 | + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); | |
18993 | + if (ret && ret != -ENODEV) { | |
18994 | + spin_lock_irqsave(&tp->rx_lock, flags); | |
18995 | + list_add_tail(&agg->list, &tp->rx_done); | |
18996 | + spin_unlock_irqrestore(&tp->rx_lock, flags); | |
18997 | + tasklet_schedule(&tp->tl); | |
18998 | + } | |
18999 | + } | |
19000 | +} | |
19001 | + | |
19002 | +static void tx_bottom(struct r8152 *tp) | |
19003 | +{ | |
19004 | + int res; | |
19005 | + | |
19006 | + do { | |
19007 | + struct tx_agg *agg; | |
19008 | + | |
19009 | + if (skb_queue_empty(&tp->tx_queue)) | |
19010 | + break; | |
19011 | + | |
19012 | + agg = r8152_get_tx_agg(tp); | |
19013 | + if (!agg) | |
19014 | + break; | |
19015 | + | |
19016 | + res = r8152_tx_agg_fill(tp, agg); | |
19017 | + if (res) { | |
19018 | + struct net_device *netdev = tp->netdev; | |
19019 | + | |
19020 | + if (res == -ENODEV) { | |
19021 | + netif_device_detach(netdev); | |
19022 | + } else { | |
19023 | + struct net_device_stats *stats = &netdev->stats; | |
19024 | + unsigned long flags; | |
19025 | + | |
19026 | + netif_warn(tp, tx_err, netdev, | |
19027 | + "failed tx_urb %d\n", res); | |
19028 | + stats->tx_dropped += agg->skb_num; | |
19029 | + | |
19030 | + spin_lock_irqsave(&tp->tx_lock, flags); | |
19031 | + list_add_tail(&agg->list, &tp->tx_free); | |
19032 | + spin_unlock_irqrestore(&tp->tx_lock, flags); | |
19033 | + } | |
19034 | + } | |
19035 | + } while (res == 0); | |
19036 | +} | |
19037 | + | |
19038 | +static void bottom_half(unsigned long data) | |
19039 | +{ | |
19040 | + struct r8152 *tp; | |
19041 | + | |
19042 | + tp = (struct r8152 *)data; | |
19043 | + | |
19044 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
19045 | + return; | |
19046 | + | |
19047 | + if (!test_bit(WORK_ENABLE, &tp->flags)) | |
19048 | + return; | |
19049 | + | |
19050 | + /* When link down, the driver would cancel all bulks. */ | |
19051 | + /* This avoid the re-submitting bulk */ | |
19052 | + if (!netif_carrier_ok(tp->netdev)) | |
19053 | + return; | |
19054 | + | |
19055 | + rx_bottom(tp); | |
19056 | + tx_bottom(tp); | |
19057 | +} | |
19058 | + | |
19059 | +static | |
19060 | +int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) | |
19061 | +{ | |
19062 | + usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), | |
19063 | + agg->head, agg_buf_sz, | |
19064 | + (usb_complete_t)read_bulk_callback, agg); | |
19065 | + | |
19066 | + return usb_submit_urb(agg->urb, mem_flags); | |
19067 | +} | |
19068 | + | |
19069 | +static void rtl_drop_queued_tx(struct r8152 *tp) | |
19070 | +{ | |
19071 | + struct net_device_stats *stats = &tp->netdev->stats; | |
19072 | + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; | |
19073 | + struct sk_buff *skb; | |
19074 | + | |
19075 | + if (skb_queue_empty(tx_queue)) | |
19076 | + return; | |
19077 | + | |
19078 | + __skb_queue_head_init(&skb_head); | |
19079 | + spin_lock_bh(&tx_queue->lock); | |
19080 | + skb_queue_splice_init(tx_queue, &skb_head); | |
19081 | + spin_unlock_bh(&tx_queue->lock); | |
19082 | + | |
19083 | + while ((skb = __skb_dequeue(&skb_head))) { | |
19084 | + dev_kfree_skb(skb); | |
19085 | + stats->tx_dropped++; | |
19086 | + } | |
19087 | +} | |
19088 | + | |
19089 | +static void rtl8152_tx_timeout(struct net_device *netdev) | |
19090 | +{ | |
19091 | + struct r8152 *tp = netdev_priv(netdev); | |
19092 | + int i; | |
19093 | + | |
19094 | + netif_warn(tp, tx_err, netdev, "Tx timeout\n"); | |
19095 | + for (i = 0; i < RTL8152_MAX_TX; i++) | |
19096 | + usb_unlink_urb(tp->tx_info[i].urb); | |
19097 | +} | |
19098 | + | |
19099 | +static void rtl8152_set_rx_mode(struct net_device *netdev) | |
19100 | +{ | |
19101 | + struct r8152 *tp = netdev_priv(netdev); | |
19102 | + | |
19103 | + if (tp->speed & LINK_STATUS) { | |
19104 | + set_bit(RTL8152_SET_RX_MODE, &tp->flags); | |
19105 | + schedule_delayed_work(&tp->schedule, 0); | |
19106 | + } | |
19107 | +} | |
19108 | + | |
19109 | +static void _rtl8152_set_rx_mode(struct net_device *netdev) | |
19110 | +{ | |
19111 | + struct r8152 *tp = netdev_priv(netdev); | |
19112 | + u32 mc_filter[2]; /* Multicast hash filter */ | |
19113 | + __le32 tmp[2]; | |
19114 | + u32 ocp_data; | |
19115 | + | |
19116 | + clear_bit(RTL8152_SET_RX_MODE, &tp->flags); | |
19117 | + netif_stop_queue(netdev); | |
19118 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19119 | + ocp_data &= ~RCR_ACPT_ALL; | |
19120 | + ocp_data |= RCR_AB | RCR_APM; | |
19121 | + | |
19122 | + if (netdev->flags & IFF_PROMISC) { | |
19123 | + /* Unconditionally log net taps. */ | |
19124 | + netif_notice(tp, link, netdev, "Promiscuous mode enabled\n"); | |
19125 | + ocp_data |= RCR_AM | RCR_AAP; | |
19126 | + mc_filter[1] = 0xffffffff; | |
19127 | + mc_filter[0] = 0xffffffff; | |
19128 | + } else if ((netdev_mc_count(netdev) > multicast_filter_limit) || | |
19129 | + (netdev->flags & IFF_ALLMULTI)) { | |
19130 | + /* Too many to filter perfectly -- accept all multicasts. */ | |
19131 | + ocp_data |= RCR_AM; | |
19132 | + mc_filter[1] = 0xffffffff; | |
19133 | + mc_filter[0] = 0xffffffff; | |
19134 | + } else { | |
19135 | + struct netdev_hw_addr *ha; | |
19136 | + | |
19137 | + mc_filter[1] = 0; | |
19138 | + mc_filter[0] = 0; | |
19139 | + netdev_for_each_mc_addr(ha, netdev) { | |
19140 | + int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
19141 | + | |
19142 | + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); | |
19143 | + ocp_data |= RCR_AM; | |
19144 | + } | |
19145 | + } | |
19146 | + | |
19147 | + tmp[0] = __cpu_to_le32(swab32(mc_filter[1])); | |
19148 | + tmp[1] = __cpu_to_le32(swab32(mc_filter[0])); | |
19149 | + | |
19150 | + pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp); | |
19151 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19152 | + netif_wake_queue(netdev); | |
19153 | +} | |
19154 | + | |
19155 | +static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, | |
19156 | + struct net_device *netdev) | |
19157 | +{ | |
19158 | + struct r8152 *tp = netdev_priv(netdev); | |
19159 | + | |
19160 | + skb_tx_timestamp(skb); | |
19161 | + | |
19162 | + skb_queue_tail(&tp->tx_queue, skb); | |
19163 | + | |
19164 | + if (!list_empty(&tp->tx_free)) { | |
19165 | + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { | |
19166 | + set_bit(SCHEDULE_TASKLET, &tp->flags); | |
19167 | + schedule_delayed_work(&tp->schedule, 0); | |
19168 | + } else { | |
19169 | + usb_mark_last_busy(tp->udev); | |
19170 | + tasklet_schedule(&tp->tl); | |
19171 | + } | |
19172 | + } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { | |
19173 | + netif_stop_queue(netdev); | |
19174 | + } | |
19175 | + | |
19176 | + return NETDEV_TX_OK; | |
19177 | +} | |
19178 | + | |
19179 | +static void r8152b_reset_packet_filter(struct r8152 *tp) | |
19180 | +{ | |
19181 | + u32 ocp_data; | |
19182 | + | |
19183 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC); | |
19184 | + ocp_data &= ~FMC_FCR_MCU_EN; | |
19185 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); | |
19186 | + ocp_data |= FMC_FCR_MCU_EN; | |
19187 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data); | |
19188 | +} | |
19189 | + | |
19190 | +static void rtl8152_nic_reset(struct r8152 *tp) | |
19191 | +{ | |
19192 | + int i; | |
19193 | + | |
19194 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST); | |
19195 | + | |
19196 | + for (i = 0; i < 1000; i++) { | |
19197 | + if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST)) | |
19198 | + break; | |
19199 | + usleep_range(100, 400); | |
19200 | + } | |
19201 | +} | |
19202 | + | |
19203 | +static void set_tx_qlen(struct r8152 *tp) | |
19204 | +{ | |
19205 | + struct net_device *netdev = tp->netdev; | |
19206 | + | |
19207 | + tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN + | |
19208 | + sizeof(struct tx_desc)); | |
19209 | +} | |
19210 | + | |
19211 | +static inline u8 rtl8152_get_speed(struct r8152 *tp) | |
19212 | +{ | |
19213 | + return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS); | |
19214 | +} | |
19215 | + | |
19216 | +static void rtl_set_eee_plus(struct r8152 *tp) | |
19217 | +{ | |
19218 | + u32 ocp_data; | |
19219 | + u8 speed; | |
19220 | + | |
19221 | + speed = rtl8152_get_speed(tp); | |
19222 | + if (speed & _10bps) { | |
19223 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); | |
19224 | + ocp_data |= EEEP_CR_EEEP_TX; | |
19225 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); | |
19226 | + } else { | |
19227 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); | |
19228 | + ocp_data &= ~EEEP_CR_EEEP_TX; | |
19229 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); | |
19230 | + } | |
19231 | +} | |
19232 | + | |
19233 | +static void rxdy_gated_en(struct r8152 *tp, bool enable) | |
19234 | +{ | |
19235 | + u32 ocp_data; | |
19236 | + | |
19237 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); | |
19238 | + if (enable) | |
19239 | + ocp_data |= RXDY_GATED_EN; | |
19240 | + else | |
19241 | + ocp_data &= ~RXDY_GATED_EN; | |
19242 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); | |
19243 | +} | |
19244 | + | |
19245 | +static int rtl_start_rx(struct r8152 *tp) | |
19246 | +{ | |
19247 | + int i, ret = 0; | |
19248 | + | |
19249 | + INIT_LIST_HEAD(&tp->rx_done); | |
19250 | + for (i = 0; i < RTL8152_MAX_RX; i++) { | |
19251 | + INIT_LIST_HEAD(&tp->rx_info[i].list); | |
19252 | + ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); | |
19253 | + if (ret) | |
19254 | + break; | |
19255 | + } | |
19256 | + | |
19257 | + return ret; | |
19258 | +} | |
19259 | + | |
19260 | +static int rtl_stop_rx(struct r8152 *tp) | |
19261 | +{ | |
19262 | + int i; | |
19263 | + | |
19264 | + for (i = 0; i < RTL8152_MAX_RX; i++) | |
19265 | + usb_kill_urb(tp->rx_info[i].urb); | |
19266 | + | |
19267 | + return 0; | |
19268 | +} | |
19269 | + | |
19270 | +static int rtl_enable(struct r8152 *tp) | |
19271 | +{ | |
19272 | + u32 ocp_data; | |
19273 | + | |
19274 | + r8152b_reset_packet_filter(tp); | |
19275 | + | |
19276 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR); | |
19277 | + ocp_data |= CR_RE | CR_TE; | |
19278 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); | |
19279 | + | |
19280 | + rxdy_gated_en(tp, false); | |
19281 | + | |
19282 | + return rtl_start_rx(tp); | |
19283 | +} | |
19284 | + | |
19285 | +static int rtl8152_enable(struct r8152 *tp) | |
19286 | +{ | |
19287 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
19288 | + return -ENODEV; | |
19289 | + | |
19290 | + set_tx_qlen(tp); | |
19291 | + rtl_set_eee_plus(tp); | |
19292 | + | |
19293 | + return rtl_enable(tp); | |
19294 | +} | |
19295 | + | |
19296 | +static void r8153_set_rx_agg(struct r8152 *tp) | |
19297 | +{ | |
19298 | + u8 speed; | |
19299 | + | |
19300 | + speed = rtl8152_get_speed(tp); | |
19301 | + if (speed & _1000bps) { | |
19302 | + if (tp->udev->speed == USB_SPEED_SUPER) { | |
19303 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, | |
19304 | + RX_THR_SUPPER); | |
19305 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, | |
19306 | + EARLY_AGG_SUPPER); | |
19307 | + } else { | |
19308 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, | |
19309 | + RX_THR_HIGH); | |
19310 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, | |
19311 | + EARLY_AGG_HIGH); | |
19312 | + } | |
19313 | + } else { | |
19314 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_SLOW); | |
19315 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, | |
19316 | + EARLY_AGG_SLOW); | |
19317 | + } | |
19318 | +} | |
19319 | + | |
19320 | +static int rtl8153_enable(struct r8152 *tp) | |
19321 | +{ | |
19322 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
19323 | + return -ENODEV; | |
19324 | + | |
19325 | + set_tx_qlen(tp); | |
19326 | + rtl_set_eee_plus(tp); | |
19327 | + r8153_set_rx_agg(tp); | |
19328 | + | |
19329 | + return rtl_enable(tp); | |
19330 | +} | |
19331 | + | |
19332 | +static void rtl_disable(struct r8152 *tp) | |
19333 | +{ | |
19334 | + u32 ocp_data; | |
19335 | + int i; | |
19336 | + | |
19337 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) { | |
19338 | + rtl_drop_queued_tx(tp); | |
19339 | + return; | |
19340 | + } | |
19341 | + | |
19342 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19343 | + ocp_data &= ~RCR_ACPT_ALL; | |
19344 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19345 | + | |
19346 | + rtl_drop_queued_tx(tp); | |
19347 | + | |
19348 | + for (i = 0; i < RTL8152_MAX_TX; i++) | |
19349 | + usb_kill_urb(tp->tx_info[i].urb); | |
19350 | + | |
19351 | + rxdy_gated_en(tp, true); | |
19352 | + | |
19353 | + for (i = 0; i < 1000; i++) { | |
19354 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19355 | + if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY) | |
19356 | + break; | |
19357 | + usleep_range(1000, 2000); | |
19358 | + } | |
19359 | + | |
19360 | + for (i = 0; i < 1000; i++) { | |
19361 | + if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY) | |
19362 | + break; | |
19363 | + usleep_range(1000, 2000); | |
19364 | + } | |
19365 | + | |
19366 | + rtl_stop_rx(tp); | |
19367 | + | |
19368 | + rtl8152_nic_reset(tp); | |
19369 | +} | |
19370 | + | |
19371 | +static void r8152_power_cut_en(struct r8152 *tp, bool enable) | |
19372 | +{ | |
19373 | + u32 ocp_data; | |
19374 | + | |
19375 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); | |
19376 | + if (enable) | |
19377 | + ocp_data |= POWER_CUT; | |
19378 | + else | |
19379 | + ocp_data &= ~POWER_CUT; | |
19380 | + ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); | |
19381 | + | |
19382 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); | |
19383 | + ocp_data &= ~RESUME_INDICATE; | |
19384 | + ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); | |
19385 | +} | |
19386 | + | |
19387 | +static void rtl_rx_vlan_en(struct r8152 *tp, bool enable) | |
19388 | +{ | |
19389 | + u32 ocp_data; | |
19390 | + | |
19391 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); | |
19392 | + if (enable) | |
19393 | + ocp_data |= CPCR_RX_VLAN; | |
19394 | + else | |
19395 | + ocp_data &= ~CPCR_RX_VLAN; | |
19396 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); | |
19397 | +} | |
19398 | + | |
19399 | +static int rtl8152_set_features(struct net_device *dev, | |
19400 | + netdev_features_t features) | |
19401 | +{ | |
19402 | + netdev_features_t changed = features ^ dev->features; | |
19403 | + struct r8152 *tp = netdev_priv(dev); | |
19404 | + int ret; | |
19405 | + | |
19406 | + ret = usb_autopm_get_interface(tp->intf); | |
19407 | + if (ret < 0) | |
19408 | + goto out; | |
19409 | + | |
19410 | + mutex_lock(&tp->control); | |
19411 | + | |
19412 | + if (changed & NETIF_F_HW_VLAN_CTAG_RX) { | |
19413 | + if (features & NETIF_F_HW_VLAN_CTAG_RX) | |
19414 | + rtl_rx_vlan_en(tp, true); | |
19415 | + else | |
19416 | + rtl_rx_vlan_en(tp, false); | |
19417 | + } | |
19418 | + | |
19419 | + mutex_unlock(&tp->control); | |
19420 | + | |
19421 | + usb_autopm_put_interface(tp->intf); | |
19422 | + | |
19423 | +out: | |
19424 | + return ret; | |
19425 | +} | |
19426 | + | |
19427 | +#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) | |
19428 | + | |
19429 | +static u32 __rtl_get_wol(struct r8152 *tp) | |
19430 | +{ | |
19431 | + u32 ocp_data; | |
19432 | + u32 wolopts = 0; | |
19433 | + | |
19434 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5); | |
19435 | + if (!(ocp_data & LAN_WAKE_EN)) | |
19436 | + return 0; | |
19437 | + | |
19438 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); | |
19439 | + if (ocp_data & LINK_ON_WAKE_EN) | |
19440 | + wolopts |= WAKE_PHY; | |
19441 | + | |
19442 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); | |
19443 | + if (ocp_data & UWF_EN) | |
19444 | + wolopts |= WAKE_UCAST; | |
19445 | + if (ocp_data & BWF_EN) | |
19446 | + wolopts |= WAKE_BCAST; | |
19447 | + if (ocp_data & MWF_EN) | |
19448 | + wolopts |= WAKE_MCAST; | |
19449 | + | |
19450 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); | |
19451 | + if (ocp_data & MAGIC_EN) | |
19452 | + wolopts |= WAKE_MAGIC; | |
19453 | + | |
19454 | + return wolopts; | |
19455 | +} | |
19456 | + | |
19457 | +static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) | |
19458 | +{ | |
19459 | + u32 ocp_data; | |
19460 | + | |
19461 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); | |
19462 | + | |
19463 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); | |
19464 | + ocp_data &= ~LINK_ON_WAKE_EN; | |
19465 | + if (wolopts & WAKE_PHY) | |
19466 | + ocp_data |= LINK_ON_WAKE_EN; | |
19467 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); | |
19468 | + | |
19469 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); | |
19470 | + ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN); | |
19471 | + if (wolopts & WAKE_UCAST) | |
19472 | + ocp_data |= UWF_EN; | |
19473 | + if (wolopts & WAKE_BCAST) | |
19474 | + ocp_data |= BWF_EN; | |
19475 | + if (wolopts & WAKE_MCAST) | |
19476 | + ocp_data |= MWF_EN; | |
19477 | + if (wolopts & WAKE_ANY) | |
19478 | + ocp_data |= LAN_WAKE_EN; | |
19479 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data); | |
19480 | + | |
19481 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); | |
19482 | + | |
19483 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); | |
19484 | + ocp_data &= ~MAGIC_EN; | |
19485 | + if (wolopts & WAKE_MAGIC) | |
19486 | + ocp_data |= MAGIC_EN; | |
19487 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); | |
19488 | + | |
19489 | + if (wolopts & WAKE_ANY) | |
19490 | + device_set_wakeup_enable(&tp->udev->dev, true); | |
19491 | + else | |
19492 | + device_set_wakeup_enable(&tp->udev->dev, false); | |
19493 | +} | |
19494 | + | |
19495 | +static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) | |
19496 | +{ | |
19497 | + if (enable) { | |
19498 | + u32 ocp_data; | |
19499 | + | |
19500 | + __rtl_set_wol(tp, WAKE_ANY); | |
19501 | + | |
19502 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); | |
19503 | + | |
19504 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); | |
19505 | + ocp_data |= LINK_OFF_WAKE_EN; | |
19506 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); | |
19507 | + | |
19508 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); | |
19509 | + } else { | |
19510 | + __rtl_set_wol(tp, tp->saved_wolopts); | |
19511 | + } | |
19512 | +} | |
19513 | + | |
19514 | +static void rtl_phy_reset(struct r8152 *tp) | |
19515 | +{ | |
19516 | + u16 data; | |
19517 | + int i; | |
19518 | + | |
19519 | + clear_bit(PHY_RESET, &tp->flags); | |
19520 | + | |
19521 | + data = r8152_mdio_read(tp, MII_BMCR); | |
19522 | + | |
19523 | + /* don't reset again before the previous one complete */ | |
19524 | + if (data & BMCR_RESET) | |
19525 | + return; | |
19526 | + | |
19527 | + data |= BMCR_RESET; | |
19528 | + r8152_mdio_write(tp, MII_BMCR, data); | |
19529 | + | |
19530 | + for (i = 0; i < 50; i++) { | |
19531 | + msleep(20); | |
19532 | + if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) | |
19533 | + break; | |
19534 | + } | |
19535 | +} | |
19536 | + | |
19537 | +static void r8153_teredo_off(struct r8152 *tp) | |
19538 | +{ | |
19539 | + u32 ocp_data; | |
19540 | + | |
19541 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); | |
19542 | + ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); | |
19543 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); | |
19544 | + | |
19545 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); | |
19546 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); | |
19547 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); | |
19548 | +} | |
19549 | + | |
19550 | +static void r8152b_disable_aldps(struct r8152 *tp) | |
19551 | +{ | |
19552 | + ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE); | |
19553 | + msleep(20); | |
19554 | +} | |
19555 | + | |
19556 | +static inline void r8152b_enable_aldps(struct r8152 *tp) | |
19557 | +{ | |
19558 | + ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | | |
19559 | + LINKENA | DIS_SDSAVE); | |
19560 | +} | |
19561 | + | |
19562 | +static void rtl8152_disable(struct r8152 *tp) | |
19563 | +{ | |
19564 | + r8152b_disable_aldps(tp); | |
19565 | + rtl_disable(tp); | |
19566 | + r8152b_enable_aldps(tp); | |
19567 | +} | |
19568 | + | |
19569 | +static void r8152b_hw_phy_cfg(struct r8152 *tp) | |
19570 | +{ | |
19571 | + u16 data; | |
19572 | + | |
19573 | + data = r8152_mdio_read(tp, MII_BMCR); | |
19574 | + if (data & BMCR_PDOWN) { | |
19575 | + data &= ~BMCR_PDOWN; | |
19576 | + r8152_mdio_write(tp, MII_BMCR, data); | |
19577 | + } | |
19578 | + | |
19579 | + set_bit(PHY_RESET, &tp->flags); | |
19580 | +} | |
19581 | + | |
19582 | +static void r8152b_exit_oob(struct r8152 *tp) | |
19583 | +{ | |
19584 | + u32 ocp_data; | |
19585 | + int i; | |
19586 | + | |
19587 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19588 | + ocp_data &= ~RCR_ACPT_ALL; | |
19589 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19590 | + | |
19591 | + rxdy_gated_en(tp, true); | |
19592 | + r8153_teredo_off(tp); | |
19593 | + r8152b_hw_phy_cfg(tp); | |
19594 | + | |
19595 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); | |
19596 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); | |
19597 | + | |
19598 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19599 | + ocp_data &= ~NOW_IS_OOB; | |
19600 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19601 | + | |
19602 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19603 | + ocp_data &= ~MCU_BORW_EN; | |
19604 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19605 | + | |
19606 | + for (i = 0; i < 1000; i++) { | |
19607 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19608 | + if (ocp_data & LINK_LIST_READY) | |
19609 | + break; | |
19610 | + usleep_range(1000, 2000); | |
19611 | + } | |
19612 | + | |
19613 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19614 | + ocp_data |= RE_INIT_LL; | |
19615 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19616 | + | |
19617 | + for (i = 0; i < 1000; i++) { | |
19618 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19619 | + if (ocp_data & LINK_LIST_READY) | |
19620 | + break; | |
19621 | + usleep_range(1000, 2000); | |
19622 | + } | |
19623 | + | |
19624 | + rtl8152_nic_reset(tp); | |
19625 | + | |
19626 | + /* rx share fifo credit full threshold */ | |
19627 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); | |
19628 | + | |
19629 | + if (tp->udev->speed == USB_SPEED_FULL || | |
19630 | + tp->udev->speed == USB_SPEED_LOW) { | |
19631 | + /* rx share fifo credit near full threshold */ | |
19632 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, | |
19633 | + RXFIFO_THR2_FULL); | |
19634 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, | |
19635 | + RXFIFO_THR3_FULL); | |
19636 | + } else { | |
19637 | + /* rx share fifo credit near full threshold */ | |
19638 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, | |
19639 | + RXFIFO_THR2_HIGH); | |
19640 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, | |
19641 | + RXFIFO_THR3_HIGH); | |
19642 | + } | |
19643 | + | |
19644 | + /* TX share fifo free credit full threshold */ | |
19645 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL); | |
19646 | + | |
19647 | + ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD); | |
19648 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH); | |
19649 | + ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA, | |
19650 | + TEST_MODE_DISABLE | TX_SIZE_ADJUST1); | |
19651 | + | |
19652 | + rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); | |
19653 | + | |
19654 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); | |
19655 | + | |
19656 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); | |
19657 | + ocp_data |= TCR0_AUTO_FIFO; | |
19658 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); | |
19659 | +} | |
19660 | + | |
19661 | +static void r8152b_enter_oob(struct r8152 *tp) | |
19662 | +{ | |
19663 | + u32 ocp_data; | |
19664 | + int i; | |
19665 | + | |
19666 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19667 | + ocp_data &= ~NOW_IS_OOB; | |
19668 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19669 | + | |
19670 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB); | |
19671 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB); | |
19672 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB); | |
19673 | + | |
19674 | + rtl_disable(tp); | |
19675 | + | |
19676 | + for (i = 0; i < 1000; i++) { | |
19677 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19678 | + if (ocp_data & LINK_LIST_READY) | |
19679 | + break; | |
19680 | + usleep_range(1000, 2000); | |
19681 | + } | |
19682 | + | |
19683 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19684 | + ocp_data |= RE_INIT_LL; | |
19685 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19686 | + | |
19687 | + for (i = 0; i < 1000; i++) { | |
19688 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19689 | + if (ocp_data & LINK_LIST_READY) | |
19690 | + break; | |
19691 | + usleep_range(1000, 2000); | |
19692 | + } | |
19693 | + | |
19694 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); | |
19695 | + | |
19696 | + rtl_rx_vlan_en(tp, true); | |
19697 | + | |
19698 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); | |
19699 | + ocp_data |= ALDPS_PROXY_MODE; | |
19700 | + ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); | |
19701 | + | |
19702 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19703 | + ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; | |
19704 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19705 | + | |
19706 | + rxdy_gated_en(tp, false); | |
19707 | + | |
19708 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19709 | + ocp_data |= RCR_APM | RCR_AM | RCR_AB; | |
19710 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19711 | +} | |
19712 | + | |
19713 | +static void r8153_hw_phy_cfg(struct r8152 *tp) | |
19714 | +{ | |
19715 | + u32 ocp_data; | |
19716 | + u16 data; | |
19717 | + | |
19718 | + ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); | |
19719 | + data = r8152_mdio_read(tp, MII_BMCR); | |
19720 | + if (data & BMCR_PDOWN) { | |
19721 | + data &= ~BMCR_PDOWN; | |
19722 | + r8152_mdio_write(tp, MII_BMCR, data); | |
19723 | + } | |
19724 | + | |
19725 | + if (tp->version == RTL_VER_03) { | |
19726 | + data = ocp_reg_read(tp, OCP_EEE_CFG); | |
19727 | + data &= ~CTAP_SHORT_EN; | |
19728 | + ocp_reg_write(tp, OCP_EEE_CFG, data); | |
19729 | + } | |
19730 | + | |
19731 | + data = ocp_reg_read(tp, OCP_POWER_CFG); | |
19732 | + data |= EEE_CLKDIV_EN; | |
19733 | + ocp_reg_write(tp, OCP_POWER_CFG, data); | |
19734 | + | |
19735 | + data = ocp_reg_read(tp, OCP_DOWN_SPEED); | |
19736 | + data |= EN_10M_BGOFF; | |
19737 | + ocp_reg_write(tp, OCP_DOWN_SPEED, data); | |
19738 | + data = ocp_reg_read(tp, OCP_POWER_CFG); | |
19739 | + data |= EN_10M_PLLOFF; | |
19740 | + ocp_reg_write(tp, OCP_POWER_CFG, data); | |
19741 | + data = sram_read(tp, SRAM_IMPEDANCE); | |
19742 | + data &= ~RX_DRIVING_MASK; | |
19743 | + sram_write(tp, SRAM_IMPEDANCE, data); | |
19744 | + | |
19745 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); | |
19746 | + ocp_data |= PFM_PWM_SWITCH; | |
19747 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); | |
19748 | + | |
19749 | + data = sram_read(tp, SRAM_LPF_CFG); | |
19750 | + data |= LPF_AUTO_TUNE; | |
19751 | + sram_write(tp, SRAM_LPF_CFG, data); | |
19752 | + | |
19753 | + data = sram_read(tp, SRAM_10M_AMP1); | |
19754 | + data |= GDAC_IB_UPALL; | |
19755 | + sram_write(tp, SRAM_10M_AMP1, data); | |
19756 | + data = sram_read(tp, SRAM_10M_AMP2); | |
19757 | + data |= AMP_DN; | |
19758 | + sram_write(tp, SRAM_10M_AMP2, data); | |
19759 | + | |
19760 | + set_bit(PHY_RESET, &tp->flags); | |
19761 | +} | |
19762 | + | |
19763 | +static void r8153_u1u2en(struct r8152 *tp, bool enable) | |
19764 | +{ | |
19765 | + u8 u1u2[8]; | |
19766 | + | |
19767 | + if (enable) | |
19768 | + memset(u1u2, 0xff, sizeof(u1u2)); | |
19769 | + else | |
19770 | + memset(u1u2, 0x00, sizeof(u1u2)); | |
19771 | + | |
19772 | + usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); | |
19773 | +} | |
19774 | + | |
19775 | +static void r8153_u2p3en(struct r8152 *tp, bool enable) | |
19776 | +{ | |
19777 | + u32 ocp_data; | |
19778 | + | |
19779 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); | |
19780 | + if (enable) | |
19781 | + ocp_data |= U2P3_ENABLE; | |
19782 | + else | |
19783 | + ocp_data &= ~U2P3_ENABLE; | |
19784 | + ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); | |
19785 | +} | |
19786 | + | |
19787 | +static void r8153_power_cut_en(struct r8152 *tp, bool enable) | |
19788 | +{ | |
19789 | + u32 ocp_data; | |
19790 | + | |
19791 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); | |
19792 | + if (enable) | |
19793 | + ocp_data |= PWR_EN | PHASE2_EN; | |
19794 | + else | |
19795 | + ocp_data &= ~(PWR_EN | PHASE2_EN); | |
19796 | + ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); | |
19797 | + | |
19798 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); | |
19799 | + ocp_data &= ~PCUT_STATUS; | |
19800 | + ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); | |
19801 | +} | |
19802 | + | |
19803 | +static void r8153_first_init(struct r8152 *tp) | |
19804 | +{ | |
19805 | + u32 ocp_data; | |
19806 | + int i; | |
19807 | + | |
19808 | + rxdy_gated_en(tp, true); | |
19809 | + r8153_teredo_off(tp); | |
19810 | + | |
19811 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19812 | + ocp_data &= ~RCR_ACPT_ALL; | |
19813 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19814 | + | |
19815 | + r8153_hw_phy_cfg(tp); | |
19816 | + | |
19817 | + rtl8152_nic_reset(tp); | |
19818 | + | |
19819 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19820 | + ocp_data &= ~NOW_IS_OOB; | |
19821 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19822 | + | |
19823 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19824 | + ocp_data &= ~MCU_BORW_EN; | |
19825 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19826 | + | |
19827 | + for (i = 0; i < 1000; i++) { | |
19828 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19829 | + if (ocp_data & LINK_LIST_READY) | |
19830 | + break; | |
19831 | + usleep_range(1000, 2000); | |
19832 | + } | |
19833 | + | |
19834 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19835 | + ocp_data |= RE_INIT_LL; | |
19836 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19837 | + | |
19838 | + for (i = 0; i < 1000; i++) { | |
19839 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19840 | + if (ocp_data & LINK_LIST_READY) | |
19841 | + break; | |
19842 | + usleep_range(1000, 2000); | |
19843 | + } | |
19844 | + | |
19845 | + rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); | |
19846 | + | |
19847 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); | |
19848 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); | |
19849 | + | |
19850 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); | |
19851 | + ocp_data |= TCR0_AUTO_FIFO; | |
19852 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); | |
19853 | + | |
19854 | + rtl8152_nic_reset(tp); | |
19855 | + | |
19856 | + /* rx share fifo credit full threshold */ | |
19857 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); | |
19858 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL); | |
19859 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL); | |
19860 | + /* TX share fifo free credit full threshold */ | |
19861 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); | |
19862 | + | |
19863 | + /* rx aggregation */ | |
19864 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); | |
19865 | + ocp_data &= ~RX_AGG_DISABLE; | |
19866 | + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); | |
19867 | +} | |
19868 | + | |
19869 | +static void r8153_enter_oob(struct r8152 *tp) | |
19870 | +{ | |
19871 | + u32 ocp_data; | |
19872 | + int i; | |
19873 | + | |
19874 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19875 | + ocp_data &= ~NOW_IS_OOB; | |
19876 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19877 | + | |
19878 | + rtl_disable(tp); | |
19879 | + | |
19880 | + for (i = 0; i < 1000; i++) { | |
19881 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19882 | + if (ocp_data & LINK_LIST_READY) | |
19883 | + break; | |
19884 | + usleep_range(1000, 2000); | |
19885 | + } | |
19886 | + | |
19887 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); | |
19888 | + ocp_data |= RE_INIT_LL; | |
19889 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); | |
19890 | + | |
19891 | + for (i = 0; i < 1000; i++) { | |
19892 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19893 | + if (ocp_data & LINK_LIST_READY) | |
19894 | + break; | |
19895 | + usleep_range(1000, 2000); | |
19896 | + } | |
19897 | + | |
19898 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); | |
19899 | + | |
19900 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); | |
19901 | + ocp_data &= ~TEREDO_WAKE_MASK; | |
19902 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); | |
19903 | + | |
19904 | + rtl_rx_vlan_en(tp, true); | |
19905 | + | |
19906 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); | |
19907 | + ocp_data |= ALDPS_PROXY_MODE; | |
19908 | + ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); | |
19909 | + | |
19910 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); | |
19911 | + ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; | |
19912 | + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); | |
19913 | + | |
19914 | + rxdy_gated_en(tp, false); | |
19915 | + | |
19916 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); | |
19917 | + ocp_data |= RCR_APM | RCR_AM | RCR_AB; | |
19918 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); | |
19919 | +} | |
19920 | + | |
19921 | +static void r8153_disable_aldps(struct r8152 *tp) | |
19922 | +{ | |
19923 | + u16 data; | |
19924 | + | |
19925 | + data = ocp_reg_read(tp, OCP_POWER_CFG); | |
19926 | + data &= ~EN_ALDPS; | |
19927 | + ocp_reg_write(tp, OCP_POWER_CFG, data); | |
19928 | + msleep(20); | |
19929 | +} | |
19930 | + | |
19931 | +static void r8153_enable_aldps(struct r8152 *tp) | |
19932 | +{ | |
19933 | + u16 data; | |
19934 | + | |
19935 | + data = ocp_reg_read(tp, OCP_POWER_CFG); | |
19936 | + data |= EN_ALDPS; | |
19937 | + ocp_reg_write(tp, OCP_POWER_CFG, data); | |
19938 | +} | |
19939 | + | |
19940 | +static void rtl8153_disable(struct r8152 *tp) | |
19941 | +{ | |
19942 | + r8153_disable_aldps(tp); | |
19943 | + rtl_disable(tp); | |
19944 | + r8153_enable_aldps(tp); | |
19945 | +} | |
19946 | + | |
19947 | +static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) | |
19948 | +{ | |
19949 | + u16 bmcr, anar, gbcr; | |
19950 | + int ret = 0; | |
19951 | + | |
19952 | + cancel_delayed_work_sync(&tp->schedule); | |
19953 | + anar = r8152_mdio_read(tp, MII_ADVERTISE); | |
19954 | + anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | | |
19955 | + ADVERTISE_100HALF | ADVERTISE_100FULL); | |
19956 | + if (tp->mii.supports_gmii) { | |
19957 | + gbcr = r8152_mdio_read(tp, MII_CTRL1000); | |
19958 | + gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); | |
19959 | + } else { | |
19960 | + gbcr = 0; | |
19961 | + } | |
19962 | + | |
19963 | + if (autoneg == AUTONEG_DISABLE) { | |
19964 | + if (speed == SPEED_10) { | |
19965 | + bmcr = 0; | |
19966 | + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; | |
19967 | + } else if (speed == SPEED_100) { | |
19968 | + bmcr = BMCR_SPEED100; | |
19969 | + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; | |
19970 | + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { | |
19971 | + bmcr = BMCR_SPEED1000; | |
19972 | + gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; | |
19973 | + } else { | |
19974 | + ret = -EINVAL; | |
19975 | + goto out; | |
19976 | + } | |
19977 | + | |
19978 | + if (duplex == DUPLEX_FULL) | |
19979 | + bmcr |= BMCR_FULLDPLX; | |
19980 | + } else { | |
19981 | + if (speed == SPEED_10) { | |
19982 | + if (duplex == DUPLEX_FULL) | |
19983 | + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; | |
19984 | + else | |
19985 | + anar |= ADVERTISE_10HALF; | |
19986 | + } else if (speed == SPEED_100) { | |
19987 | + if (duplex == DUPLEX_FULL) { | |
19988 | + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; | |
19989 | + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; | |
19990 | + } else { | |
19991 | + anar |= ADVERTISE_10HALF; | |
19992 | + anar |= ADVERTISE_100HALF; | |
19993 | + } | |
19994 | + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { | |
19995 | + if (duplex == DUPLEX_FULL) { | |
19996 | + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; | |
19997 | + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; | |
19998 | + gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; | |
19999 | + } else { | |
20000 | + anar |= ADVERTISE_10HALF; | |
20001 | + anar |= ADVERTISE_100HALF; | |
20002 | + gbcr |= ADVERTISE_1000HALF; | |
20003 | + } | |
20004 | + } else { | |
20005 | + ret = -EINVAL; | |
20006 | + goto out; | |
20007 | + } | |
20008 | + | |
20009 | + bmcr = BMCR_ANENABLE | BMCR_ANRESTART; | |
20010 | + } | |
20011 | + | |
20012 | + if (test_bit(PHY_RESET, &tp->flags)) | |
20013 | + bmcr |= BMCR_RESET; | |
20014 | + | |
20015 | + if (tp->mii.supports_gmii) | |
20016 | + r8152_mdio_write(tp, MII_CTRL1000, gbcr); | |
20017 | + | |
20018 | + r8152_mdio_write(tp, MII_ADVERTISE, anar); | |
20019 | + r8152_mdio_write(tp, MII_BMCR, bmcr); | |
20020 | + | |
20021 | + if (test_bit(PHY_RESET, &tp->flags)) { | |
20022 | + int i; | |
20023 | + | |
20024 | + clear_bit(PHY_RESET, &tp->flags); | |
20025 | + for (i = 0; i < 50; i++) { | |
20026 | + msleep(20); | |
20027 | + if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) | |
20028 | + break; | |
20029 | + } | |
20030 | + } | |
20031 | + | |
20032 | +out: | |
20033 | + | |
20034 | + return ret; | |
20035 | +} | |
20036 | + | |
20037 | +static void rtl8152_up(struct r8152 *tp) | |
20038 | +{ | |
20039 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20040 | + return; | |
20041 | + | |
20042 | + r8152b_disable_aldps(tp); | |
20043 | + r8152b_exit_oob(tp); | |
20044 | + r8152b_enable_aldps(tp); | |
20045 | +} | |
20046 | + | |
20047 | +static void rtl8152_down(struct r8152 *tp) | |
20048 | +{ | |
20049 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) { | |
20050 | + rtl_drop_queued_tx(tp); | |
20051 | + return; | |
20052 | + } | |
20053 | + | |
20054 | + r8152_power_cut_en(tp, false); | |
20055 | + r8152b_disable_aldps(tp); | |
20056 | + r8152b_enter_oob(tp); | |
20057 | + r8152b_enable_aldps(tp); | |
20058 | +} | |
20059 | + | |
20060 | +static void rtl8153_up(struct r8152 *tp) | |
20061 | +{ | |
20062 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20063 | + return; | |
20064 | + | |
20065 | + r8153_disable_aldps(tp); | |
20066 | + r8153_first_init(tp); | |
20067 | + r8153_enable_aldps(tp); | |
20068 | +} | |
20069 | + | |
20070 | +static void rtl8153_down(struct r8152 *tp) | |
20071 | +{ | |
20072 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) { | |
20073 | + rtl_drop_queued_tx(tp); | |
20074 | + return; | |
20075 | + } | |
20076 | + | |
20077 | + r8153_u1u2en(tp, false); | |
20078 | + r8153_power_cut_en(tp, false); | |
20079 | + r8153_disable_aldps(tp); | |
20080 | + r8153_enter_oob(tp); | |
20081 | + r8153_enable_aldps(tp); | |
20082 | +} | |
20083 | + | |
20084 | +static void set_carrier(struct r8152 *tp) | |
20085 | +{ | |
20086 | + struct net_device *netdev = tp->netdev; | |
20087 | + u8 speed; | |
20088 | + | |
20089 | + clear_bit(RTL8152_LINK_CHG, &tp->flags); | |
20090 | + speed = rtl8152_get_speed(tp); | |
20091 | + | |
20092 | + if (speed & LINK_STATUS) { | |
20093 | + if (!(tp->speed & LINK_STATUS)) { | |
20094 | + tp->rtl_ops.enable(tp); | |
20095 | + set_bit(RTL8152_SET_RX_MODE, &tp->flags); | |
20096 | + netif_carrier_on(netdev); | |
20097 | + } | |
20098 | + } else { | |
20099 | + if (tp->speed & LINK_STATUS) { | |
20100 | + netif_carrier_off(netdev); | |
20101 | + tasklet_disable(&tp->tl); | |
20102 | + tp->rtl_ops.disable(tp); | |
20103 | + tasklet_enable(&tp->tl); | |
20104 | + } | |
20105 | + } | |
20106 | + tp->speed = speed; | |
20107 | +} | |
20108 | + | |
20109 | +static void rtl_work_func_t(struct work_struct *work) | |
20110 | +{ | |
20111 | + struct r8152 *tp = container_of(work, struct r8152, schedule.work); | |
20112 | + | |
20113 | + if (usb_autopm_get_interface(tp->intf) < 0) | |
20114 | + return; | |
20115 | + | |
20116 | + if (!test_bit(WORK_ENABLE, &tp->flags)) | |
20117 | + goto out1; | |
20118 | + | |
20119 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20120 | + goto out1; | |
20121 | + | |
20122 | + if (!mutex_trylock(&tp->control)) { | |
20123 | + schedule_delayed_work(&tp->schedule, 0); | |
20124 | + goto out1; | |
20125 | + } | |
20126 | + | |
20127 | + if (test_bit(RTL8152_LINK_CHG, &tp->flags)) | |
20128 | + set_carrier(tp); | |
20129 | + | |
20130 | + if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) | |
20131 | + _rtl8152_set_rx_mode(tp->netdev); | |
20132 | + | |
20133 | + if (test_bit(SCHEDULE_TASKLET, &tp->flags) && | |
20134 | + (tp->speed & LINK_STATUS)) { | |
20135 | + clear_bit(SCHEDULE_TASKLET, &tp->flags); | |
20136 | + tasklet_schedule(&tp->tl); | |
20137 | + } | |
20138 | + | |
20139 | + if (test_bit(PHY_RESET, &tp->flags)) | |
20140 | + rtl_phy_reset(tp); | |
20141 | + | |
20142 | + mutex_unlock(&tp->control); | |
20143 | + | |
20144 | +out1: | |
20145 | + usb_autopm_put_interface(tp->intf); | |
20146 | +} | |
20147 | + | |
20148 | +static int rtl8152_open(struct net_device *netdev) | |
20149 | +{ | |
20150 | + struct r8152 *tp = netdev_priv(netdev); | |
20151 | + int res = 0; | |
20152 | + | |
20153 | + res = alloc_all_mem(tp); | |
20154 | + if (res) | |
20155 | + goto out; | |
20156 | + | |
20157 | + /* set speed to 0 to avoid autoresume try to submit rx */ | |
20158 | + tp->speed = 0; | |
20159 | + | |
20160 | + res = usb_autopm_get_interface(tp->intf); | |
20161 | + if (res < 0) { | |
20162 | + free_all_mem(tp); | |
20163 | + goto out; | |
20164 | + } | |
20165 | + | |
20166 | + mutex_lock(&tp->control); | |
20167 | + | |
20168 | + /* The WORK_ENABLE may be set when autoresume occurs */ | |
20169 | + if (test_bit(WORK_ENABLE, &tp->flags)) { | |
20170 | + clear_bit(WORK_ENABLE, &tp->flags); | |
20171 | + usb_kill_urb(tp->intr_urb); | |
20172 | + cancel_delayed_work_sync(&tp->schedule); | |
20173 | + | |
20174 | + /* disable the tx/rx, if the workqueue has enabled them. */ | |
20175 | + if (tp->speed & LINK_STATUS) | |
20176 | + tp->rtl_ops.disable(tp); | |
20177 | + } | |
20178 | + | |
20179 | + tp->rtl_ops.up(tp); | |
20180 | + | |
20181 | + rtl8152_set_speed(tp, AUTONEG_ENABLE, | |
20182 | + tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, | |
20183 | + DUPLEX_FULL); | |
20184 | + tp->speed = 0; | |
20185 | + netif_carrier_off(netdev); | |
20186 | + netif_start_queue(netdev); | |
20187 | + set_bit(WORK_ENABLE, &tp->flags); | |
20188 | + | |
20189 | + res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); | |
20190 | + if (res) { | |
20191 | + if (res == -ENODEV) | |
20192 | + netif_device_detach(tp->netdev); | |
20193 | + netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", | |
20194 | + res); | |
20195 | + free_all_mem(tp); | |
20196 | + } | |
20197 | + | |
20198 | + mutex_unlock(&tp->control); | |
20199 | + | |
20200 | + usb_autopm_put_interface(tp->intf); | |
20201 | + | |
20202 | +out: | |
20203 | + return res; | |
20204 | +} | |
20205 | + | |
20206 | +static int rtl8152_close(struct net_device *netdev) | |
20207 | +{ | |
20208 | + struct r8152 *tp = netdev_priv(netdev); | |
20209 | + int res = 0; | |
20210 | + | |
20211 | + clear_bit(WORK_ENABLE, &tp->flags); | |
20212 | + usb_kill_urb(tp->intr_urb); | |
20213 | + cancel_delayed_work_sync(&tp->schedule); | |
20214 | + netif_stop_queue(netdev); | |
20215 | + | |
20216 | + res = usb_autopm_get_interface(tp->intf); | |
20217 | + if (res < 0) { | |
20218 | + rtl_drop_queued_tx(tp); | |
20219 | + } else { | |
20220 | + mutex_lock(&tp->control); | |
20221 | + | |
20222 | + /* The autosuspend may have been enabled and wouldn't | |
20223 | + * be disable when autoresume occurs, because the | |
20224 | + * netif_running() would be false. | |
20225 | + */ | |
20226 | + rtl_runtime_suspend_enable(tp, false); | |
20227 | + | |
20228 | + tasklet_disable(&tp->tl); | |
20229 | + tp->rtl_ops.down(tp); | |
20230 | + tasklet_enable(&tp->tl); | |
20231 | + | |
20232 | + mutex_unlock(&tp->control); | |
20233 | + | |
20234 | + usb_autopm_put_interface(tp->intf); | |
20235 | + } | |
20236 | + | |
20237 | + free_all_mem(tp); | |
20238 | + | |
20239 | + return res; | |
20240 | +} | |
20241 | + | |
20242 | +static inline void r8152_mmd_indirect(struct r8152 *tp, u16 dev, u16 reg) | |
20243 | +{ | |
20244 | + ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | dev); | |
20245 | + ocp_reg_write(tp, OCP_EEE_DATA, reg); | |
20246 | + ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | dev); | |
20247 | +} | |
20248 | + | |
20249 | +static u16 r8152_mmd_read(struct r8152 *tp, u16 dev, u16 reg) | |
20250 | +{ | |
20251 | + u16 data; | |
20252 | + | |
20253 | + r8152_mmd_indirect(tp, dev, reg); | |
20254 | + data = ocp_reg_read(tp, OCP_EEE_DATA); | |
20255 | + ocp_reg_write(tp, OCP_EEE_AR, 0x0000); | |
20256 | + | |
20257 | + return data; | |
20258 | +} | |
20259 | + | |
20260 | +static void r8152_mmd_write(struct r8152 *tp, u16 dev, u16 reg, u16 data) | |
20261 | +{ | |
20262 | + r8152_mmd_indirect(tp, dev, reg); | |
20263 | + ocp_reg_write(tp, OCP_EEE_DATA, data); | |
20264 | + ocp_reg_write(tp, OCP_EEE_AR, 0x0000); | |
20265 | +} | |
20266 | + | |
20267 | +static void r8152_eee_en(struct r8152 *tp, bool enable) | |
20268 | +{ | |
20269 | + u16 config1, config2, config3; | |
20270 | + u32 ocp_data; | |
20271 | + | |
20272 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); | |
20273 | + config1 = ocp_reg_read(tp, OCP_EEE_CONFIG1) & ~sd_rise_time_mask; | |
20274 | + config2 = ocp_reg_read(tp, OCP_EEE_CONFIG2); | |
20275 | + config3 = ocp_reg_read(tp, OCP_EEE_CONFIG3) & ~fast_snr_mask; | |
20276 | + | |
20277 | + if (enable) { | |
20278 | + ocp_data |= EEE_RX_EN | EEE_TX_EN; | |
20279 | + config1 |= EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | RX_QUIET_EN; | |
20280 | + config1 |= sd_rise_time(1); | |
20281 | + config2 |= RG_DACQUIET_EN | RG_LDVQUIET_EN; | |
20282 | + config3 |= fast_snr(42); | |
20283 | + } else { | |
20284 | + ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); | |
20285 | + config1 &= ~(EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | | |
20286 | + RX_QUIET_EN); | |
20287 | + config1 |= sd_rise_time(7); | |
20288 | + config2 &= ~(RG_DACQUIET_EN | RG_LDVQUIET_EN); | |
20289 | + config3 |= fast_snr(511); | |
20290 | + } | |
20291 | + | |
20292 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); | |
20293 | + ocp_reg_write(tp, OCP_EEE_CONFIG1, config1); | |
20294 | + ocp_reg_write(tp, OCP_EEE_CONFIG2, config2); | |
20295 | + ocp_reg_write(tp, OCP_EEE_CONFIG3, config3); | |
20296 | +} | |
20297 | + | |
20298 | +static void r8152b_enable_eee(struct r8152 *tp) | |
20299 | +{ | |
20300 | + r8152_eee_en(tp, true); | |
20301 | + r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, MDIO_EEE_100TX); | |
20302 | +} | |
20303 | + | |
20304 | +static void r8153_eee_en(struct r8152 *tp, bool enable) | |
20305 | +{ | |
20306 | + u32 ocp_data; | |
20307 | + u16 config; | |
20308 | + | |
20309 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); | |
20310 | + config = ocp_reg_read(tp, OCP_EEE_CFG); | |
20311 | + | |
20312 | + if (enable) { | |
20313 | + ocp_data |= EEE_RX_EN | EEE_TX_EN; | |
20314 | + config |= EEE10_EN; | |
20315 | + } else { | |
20316 | + ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); | |
20317 | + config &= ~EEE10_EN; | |
20318 | + } | |
20319 | + | |
20320 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); | |
20321 | + ocp_reg_write(tp, OCP_EEE_CFG, config); | |
20322 | +} | |
20323 | + | |
20324 | +static void r8153_enable_eee(struct r8152 *tp) | |
20325 | +{ | |
20326 | + r8153_eee_en(tp, true); | |
20327 | + ocp_reg_write(tp, OCP_EEE_ADV, MDIO_EEE_1000T | MDIO_EEE_100TX); | |
20328 | +} | |
20329 | + | |
20330 | +static void r8152b_enable_fc(struct r8152 *tp) | |
20331 | +{ | |
20332 | + u16 anar; | |
20333 | + | |
20334 | + anar = r8152_mdio_read(tp, MII_ADVERTISE); | |
20335 | + anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; | |
20336 | + r8152_mdio_write(tp, MII_ADVERTISE, anar); | |
20337 | +} | |
20338 | + | |
20339 | +static void rtl_tally_reset(struct r8152 *tp) | |
20340 | +{ | |
20341 | + u32 ocp_data; | |
20342 | + | |
20343 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); | |
20344 | + ocp_data |= TALLY_RESET; | |
20345 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); | |
20346 | +} | |
20347 | + | |
20348 | +static void r8152b_init(struct r8152 *tp) | |
20349 | +{ | |
20350 | + u32 ocp_data; | |
20351 | + | |
20352 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20353 | + return; | |
20354 | + | |
20355 | + r8152b_disable_aldps(tp); | |
20356 | + | |
20357 | + if (tp->version == RTL_VER_01) { | |
20358 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); | |
20359 | + ocp_data &= ~LED_MODE_MASK; | |
20360 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); | |
20361 | + } | |
20362 | + | |
20363 | + r8152_power_cut_en(tp, false); | |
20364 | + | |
20365 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); | |
20366 | + ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; | |
20367 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); | |
20368 | + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL); | |
20369 | + ocp_data &= ~MCU_CLK_RATIO_MASK; | |
20370 | + ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN; | |
20371 | + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data); | |
20372 | + ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK | | |
20373 | + SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK; | |
20374 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data); | |
20375 | + | |
20376 | + r8152b_enable_eee(tp); | |
20377 | + r8152b_enable_aldps(tp); | |
20378 | + r8152b_enable_fc(tp); | |
20379 | + rtl_tally_reset(tp); | |
20380 | + | |
20381 | + /* enable rx aggregation */ | |
20382 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); | |
20383 | + ocp_data &= ~RX_AGG_DISABLE; | |
20384 | + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); | |
20385 | +} | |
20386 | + | |
20387 | +static void r8153_init(struct r8152 *tp) | |
20388 | +{ | |
20389 | + u32 ocp_data; | |
20390 | + int i; | |
20391 | + | |
20392 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20393 | + return; | |
20394 | + | |
20395 | + r8153_disable_aldps(tp); | |
20396 | + r8153_u1u2en(tp, false); | |
20397 | + | |
20398 | + for (i = 0; i < 500; i++) { | |
20399 | + if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & | |
20400 | + AUTOLOAD_DONE) | |
20401 | + break; | |
20402 | + msleep(20); | |
20403 | + } | |
20404 | + | |
20405 | + for (i = 0; i < 500; i++) { | |
20406 | + ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; | |
20407 | + if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN) | |
20408 | + break; | |
20409 | + msleep(20); | |
20410 | + } | |
20411 | + | |
20412 | + r8153_u2p3en(tp, false); | |
20413 | + | |
20414 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); | |
20415 | + ocp_data &= ~TIMER11_EN; | |
20416 | + ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); | |
20417 | + | |
20418 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); | |
20419 | + ocp_data &= ~LED_MODE_MASK; | |
20420 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); | |
20421 | + | |
20422 | + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); | |
20423 | + ocp_data &= ~LPM_TIMER_MASK; | |
20424 | + if (tp->udev->speed == USB_SPEED_SUPER) | |
20425 | + ocp_data |= LPM_TIMER_500US; | |
20426 | + else | |
20427 | + ocp_data |= LPM_TIMER_500MS; | |
20428 | + ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); | |
20429 | + | |
20430 | + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); | |
20431 | + ocp_data &= ~SEN_VAL_MASK; | |
20432 | + ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; | |
20433 | + ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); | |
20434 | + | |
20435 | + r8153_power_cut_en(tp, false); | |
20436 | + r8153_u1u2en(tp, true); | |
20437 | + | |
20438 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO); | |
20439 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO); | |
20440 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, | |
20441 | + PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN | | |
20442 | + U1U2_SPDWN_EN | L1_SPDWN_EN); | |
20443 | + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, | |
20444 | + PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN | | |
20445 | + TP100_SPDWN_EN | TP500_SPDWN_EN | TP1000_SPDWN_EN | | |
20446 | + EEE_SPDWN_EN); | |
20447 | + | |
20448 | + r8153_enable_eee(tp); | |
20449 | + r8153_enable_aldps(tp); | |
20450 | + r8152b_enable_fc(tp); | |
20451 | + rtl_tally_reset(tp); | |
20452 | +} | |
20453 | + | |
20454 | +static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) | |
20455 | +{ | |
20456 | + struct r8152 *tp = usb_get_intfdata(intf); | |
20457 | + struct net_device *netdev = tp->netdev; | |
20458 | + int ret = 0; | |
20459 | + | |
20460 | + mutex_lock(&tp->control); | |
20461 | + | |
20462 | + if (PMSG_IS_AUTO(message)) { | |
20463 | + if (netif_running(netdev) && work_busy(&tp->schedule.work)) { | |
20464 | + ret = -EBUSY; | |
20465 | + goto out1; | |
20466 | + } | |
20467 | + | |
20468 | + set_bit(SELECTIVE_SUSPEND, &tp->flags); | |
20469 | + } else { | |
20470 | + netif_device_detach(netdev); | |
20471 | + } | |
20472 | + | |
20473 | + if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { | |
20474 | + clear_bit(WORK_ENABLE, &tp->flags); | |
20475 | + usb_kill_urb(tp->intr_urb); | |
20476 | + tasklet_disable(&tp->tl); | |
20477 | + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { | |
20478 | + rtl_stop_rx(tp); | |
20479 | + rtl_runtime_suspend_enable(tp, true); | |
20480 | + } else { | |
20481 | + cancel_delayed_work_sync(&tp->schedule); | |
20482 | + tp->rtl_ops.down(tp); | |
20483 | + } | |
20484 | + tasklet_enable(&tp->tl); | |
20485 | + } | |
20486 | +out1: | |
20487 | + mutex_unlock(&tp->control); | |
20488 | + | |
20489 | + return ret; | |
20490 | +} | |
20491 | + | |
20492 | +static int rtl8152_resume(struct usb_interface *intf) | |
20493 | +{ | |
20494 | + struct r8152 *tp = usb_get_intfdata(intf); | |
20495 | + | |
20496 | + mutex_lock(&tp->control); | |
20497 | + | |
20498 | + if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { | |
20499 | + tp->rtl_ops.init(tp); | |
20500 | + netif_device_attach(tp->netdev); | |
20501 | + } | |
20502 | + | |
20503 | + if (netif_running(tp->netdev)) { | |
20504 | + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { | |
20505 | + rtl_runtime_suspend_enable(tp, false); | |
20506 | + clear_bit(SELECTIVE_SUSPEND, &tp->flags); | |
20507 | + set_bit(WORK_ENABLE, &tp->flags); | |
20508 | + if (tp->speed & LINK_STATUS) | |
20509 | + rtl_start_rx(tp); | |
20510 | + } else { | |
20511 | + tp->rtl_ops.up(tp); | |
20512 | + rtl8152_set_speed(tp, AUTONEG_ENABLE, | |
20513 | + tp->mii.supports_gmii ? | |
20514 | + SPEED_1000 : SPEED_100, | |
20515 | + DUPLEX_FULL); | |
20516 | + tp->speed = 0; | |
20517 | + netif_carrier_off(tp->netdev); | |
20518 | + set_bit(WORK_ENABLE, &tp->flags); | |
20519 | + } | |
20520 | + usb_submit_urb(tp->intr_urb, GFP_KERNEL); | |
20521 | + } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { | |
20522 | + clear_bit(SELECTIVE_SUSPEND, &tp->flags); | |
20523 | + } | |
20524 | + | |
20525 | + mutex_unlock(&tp->control); | |
20526 | + | |
20527 | + return 0; | |
20528 | +} | |
20529 | + | |
20530 | +static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
20531 | +{ | |
20532 | + struct r8152 *tp = netdev_priv(dev); | |
20533 | + | |
20534 | + if (usb_autopm_get_interface(tp->intf) < 0) | |
20535 | + return; | |
20536 | + | |
20537 | + mutex_lock(&tp->control); | |
20538 | + | |
20539 | + wol->supported = WAKE_ANY; | |
20540 | + wol->wolopts = __rtl_get_wol(tp); | |
20541 | + | |
20542 | + mutex_unlock(&tp->control); | |
20543 | + | |
20544 | + usb_autopm_put_interface(tp->intf); | |
20545 | +} | |
20546 | + | |
20547 | +static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |
20548 | +{ | |
20549 | + struct r8152 *tp = netdev_priv(dev); | |
20550 | + int ret; | |
20551 | + | |
20552 | + ret = usb_autopm_get_interface(tp->intf); | |
20553 | + if (ret < 0) | |
20554 | + goto out_set_wol; | |
20555 | + | |
20556 | + mutex_lock(&tp->control); | |
20557 | + | |
20558 | + __rtl_set_wol(tp, wol->wolopts); | |
20559 | + tp->saved_wolopts = wol->wolopts & WAKE_ANY; | |
20560 | + | |
20561 | + mutex_unlock(&tp->control); | |
20562 | + | |
20563 | + usb_autopm_put_interface(tp->intf); | |
20564 | + | |
20565 | +out_set_wol: | |
20566 | + return ret; | |
20567 | +} | |
20568 | + | |
20569 | +static u32 rtl8152_get_msglevel(struct net_device *dev) | |
20570 | +{ | |
20571 | + struct r8152 *tp = netdev_priv(dev); | |
20572 | + | |
20573 | + return tp->msg_enable; | |
20574 | +} | |
20575 | + | |
20576 | +static void rtl8152_set_msglevel(struct net_device *dev, u32 value) | |
20577 | +{ | |
20578 | + struct r8152 *tp = netdev_priv(dev); | |
20579 | + | |
20580 | + tp->msg_enable = value; | |
20581 | +} | |
20582 | + | |
20583 | +static void rtl8152_get_drvinfo(struct net_device *netdev, | |
20584 | + struct ethtool_drvinfo *info) | |
20585 | +{ | |
20586 | + struct r8152 *tp = netdev_priv(netdev); | |
20587 | + | |
20588 | + strlcpy(info->driver, MODULENAME, sizeof(info->driver)); | |
20589 | + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
20590 | + usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info)); | |
20591 | +} | |
20592 | + | |
20593 | +static | |
20594 | +int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) | |
20595 | +{ | |
20596 | + struct r8152 *tp = netdev_priv(netdev); | |
20597 | + int ret; | |
20598 | + | |
20599 | + if (!tp->mii.mdio_read) | |
20600 | + return -EOPNOTSUPP; | |
20601 | + | |
20602 | + ret = usb_autopm_get_interface(tp->intf); | |
20603 | + if (ret < 0) | |
20604 | + goto out; | |
20605 | + | |
20606 | + mutex_lock(&tp->control); | |
20607 | + | |
20608 | + ret = mii_ethtool_gset(&tp->mii, cmd); | |
20609 | + | |
20610 | + mutex_unlock(&tp->control); | |
20611 | + | |
20612 | + usb_autopm_put_interface(tp->intf); | |
20613 | + | |
20614 | +out: | |
20615 | + return ret; | |
20616 | +} | |
20617 | + | |
20618 | +static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
20619 | +{ | |
20620 | + struct r8152 *tp = netdev_priv(dev); | |
20621 | + int ret; | |
20622 | + | |
20623 | + ret = usb_autopm_get_interface(tp->intf); | |
20624 | + if (ret < 0) | |
20625 | + goto out; | |
20626 | + | |
20627 | + mutex_lock(&tp->control); | |
20628 | + | |
20629 | + ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); | |
20630 | + | |
20631 | + mutex_unlock(&tp->control); | |
20632 | + | |
20633 | + usb_autopm_put_interface(tp->intf); | |
20634 | + | |
20635 | +out: | |
20636 | + return ret; | |
20637 | +} | |
20638 | + | |
20639 | +static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = { | |
20640 | + "tx_packets", | |
20641 | + "rx_packets", | |
20642 | + "tx_errors", | |
20643 | + "rx_errors", | |
20644 | + "rx_missed", | |
20645 | + "align_errors", | |
20646 | + "tx_single_collisions", | |
20647 | + "tx_multi_collisions", | |
20648 | + "rx_unicast", | |
20649 | + "rx_broadcast", | |
20650 | + "rx_multicast", | |
20651 | + "tx_aborted", | |
20652 | + "tx_underrun", | |
20653 | +}; | |
20654 | + | |
20655 | +static int rtl8152_get_sset_count(struct net_device *dev, int sset) | |
20656 | +{ | |
20657 | + switch (sset) { | |
20658 | + case ETH_SS_STATS: | |
20659 | + return ARRAY_SIZE(rtl8152_gstrings); | |
20660 | + default: | |
20661 | + return -EOPNOTSUPP; | |
20662 | + } | |
20663 | +} | |
20664 | + | |
20665 | +static void rtl8152_get_ethtool_stats(struct net_device *dev, | |
20666 | + struct ethtool_stats *stats, u64 *data) | |
20667 | +{ | |
20668 | + struct r8152 *tp = netdev_priv(dev); | |
20669 | + struct tally_counter tally; | |
20670 | + | |
20671 | + if (usb_autopm_get_interface(tp->intf) < 0) | |
20672 | + return; | |
20673 | + | |
20674 | + generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); | |
20675 | + | |
20676 | + usb_autopm_put_interface(tp->intf); | |
20677 | + | |
20678 | + data[0] = le64_to_cpu(tally.tx_packets); | |
20679 | + data[1] = le64_to_cpu(tally.rx_packets); | |
20680 | + data[2] = le64_to_cpu(tally.tx_errors); | |
20681 | + data[3] = le32_to_cpu(tally.rx_errors); | |
20682 | + data[4] = le16_to_cpu(tally.rx_missed); | |
20683 | + data[5] = le16_to_cpu(tally.align_errors); | |
20684 | + data[6] = le32_to_cpu(tally.tx_one_collision); | |
20685 | + data[7] = le32_to_cpu(tally.tx_multi_collision); | |
20686 | + data[8] = le64_to_cpu(tally.rx_unicast); | |
20687 | + data[9] = le64_to_cpu(tally.rx_broadcast); | |
20688 | + data[10] = le32_to_cpu(tally.rx_multicast); | |
20689 | + data[11] = le16_to_cpu(tally.tx_aborted); | |
20690 | + data[12] = le16_to_cpu(tally.tx_underun); | |
20691 | +} | |
20692 | + | |
20693 | +static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) | |
20694 | +{ | |
20695 | + switch (stringset) { | |
20696 | + case ETH_SS_STATS: | |
20697 | + memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings)); | |
20698 | + break; | |
20699 | + } | |
20700 | +} | |
20701 | + | |
20702 | +static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) | |
20703 | +{ | |
20704 | + u32 ocp_data, lp, adv, supported = 0; | |
20705 | + u16 val; | |
20706 | + | |
20707 | + val = r8152_mmd_read(tp, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); | |
20708 | + supported = mmd_eee_cap_to_ethtool_sup_t(val); | |
20709 | + | |
20710 | + val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV); | |
20711 | + adv = mmd_eee_adv_to_ethtool_adv_t(val); | |
20712 | + | |
20713 | + val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); | |
20714 | + lp = mmd_eee_adv_to_ethtool_adv_t(val); | |
20715 | + | |
20716 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); | |
20717 | + ocp_data &= EEE_RX_EN | EEE_TX_EN; | |
20718 | + | |
20719 | + eee->eee_enabled = !!ocp_data; | |
20720 | + eee->eee_active = !!(supported & adv & lp); | |
20721 | + eee->supported = supported; | |
20722 | + eee->advertised = adv; | |
20723 | + eee->lp_advertised = lp; | |
20724 | + | |
20725 | + return 0; | |
20726 | +} | |
20727 | + | |
20728 | +static int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) | |
20729 | +{ | |
20730 | + u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); | |
20731 | + | |
20732 | + r8152_eee_en(tp, eee->eee_enabled); | |
20733 | + | |
20734 | + if (!eee->eee_enabled) | |
20735 | + val = 0; | |
20736 | + | |
20737 | + r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); | |
20738 | + | |
20739 | + return 0; | |
20740 | +} | |
20741 | + | |
20742 | +static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) | |
20743 | +{ | |
20744 | + u32 ocp_data, lp, adv, supported = 0; | |
20745 | + u16 val; | |
20746 | + | |
20747 | + val = ocp_reg_read(tp, OCP_EEE_ABLE); | |
20748 | + supported = mmd_eee_cap_to_ethtool_sup_t(val); | |
20749 | + | |
20750 | + val = ocp_reg_read(tp, OCP_EEE_ADV); | |
20751 | + adv = mmd_eee_adv_to_ethtool_adv_t(val); | |
20752 | + | |
20753 | + val = ocp_reg_read(tp, OCP_EEE_LPABLE); | |
20754 | + lp = mmd_eee_adv_to_ethtool_adv_t(val); | |
20755 | + | |
20756 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); | |
20757 | + ocp_data &= EEE_RX_EN | EEE_TX_EN; | |
20758 | + | |
20759 | + eee->eee_enabled = !!ocp_data; | |
20760 | + eee->eee_active = !!(supported & adv & lp); | |
20761 | + eee->supported = supported; | |
20762 | + eee->advertised = adv; | |
20763 | + eee->lp_advertised = lp; | |
20764 | + | |
20765 | + return 0; | |
20766 | +} | |
20767 | + | |
20768 | +static int r8153_set_eee(struct r8152 *tp, struct ethtool_eee *eee) | |
20769 | +{ | |
20770 | + u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); | |
20771 | + | |
20772 | + r8153_eee_en(tp, eee->eee_enabled); | |
20773 | + | |
20774 | + if (!eee->eee_enabled) | |
20775 | + val = 0; | |
20776 | + | |
20777 | + ocp_reg_write(tp, OCP_EEE_ADV, val); | |
20778 | + | |
20779 | + return 0; | |
20780 | +} | |
20781 | + | |
20782 | +static int | |
20783 | +rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) | |
20784 | +{ | |
20785 | + struct r8152 *tp = netdev_priv(net); | |
20786 | + int ret; | |
20787 | + | |
20788 | + ret = usb_autopm_get_interface(tp->intf); | |
20789 | + if (ret < 0) | |
20790 | + goto out; | |
20791 | + | |
20792 | + mutex_lock(&tp->control); | |
20793 | + | |
20794 | + ret = tp->rtl_ops.eee_get(tp, edata); | |
20795 | + | |
20796 | + mutex_unlock(&tp->control); | |
20797 | + | |
20798 | + usb_autopm_put_interface(tp->intf); | |
20799 | + | |
20800 | +out: | |
20801 | + return ret; | |
20802 | +} | |
20803 | + | |
20804 | +static int | |
20805 | +rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) | |
20806 | +{ | |
20807 | + struct r8152 *tp = netdev_priv(net); | |
20808 | + int ret; | |
20809 | + | |
20810 | + ret = usb_autopm_get_interface(tp->intf); | |
20811 | + if (ret < 0) | |
20812 | + goto out; | |
20813 | + | |
20814 | + mutex_lock(&tp->control); | |
20815 | + | |
20816 | + ret = tp->rtl_ops.eee_set(tp, edata); | |
20817 | + if (!ret) | |
20818 | + ret = mii_nway_restart(&tp->mii); | |
20819 | + | |
20820 | + mutex_unlock(&tp->control); | |
20821 | + | |
20822 | + usb_autopm_put_interface(tp->intf); | |
20823 | + | |
20824 | +out: | |
20825 | + return ret; | |
20826 | +} | |
20827 | + | |
20828 | +static struct ethtool_ops ops = { | |
20829 | + .get_drvinfo = rtl8152_get_drvinfo, | |
20830 | + .get_settings = rtl8152_get_settings, | |
20831 | + .set_settings = rtl8152_set_settings, | |
20832 | + .get_link = ethtool_op_get_link, | |
20833 | + .get_msglevel = rtl8152_get_msglevel, | |
20834 | + .set_msglevel = rtl8152_set_msglevel, | |
20835 | + .get_wol = rtl8152_get_wol, | |
20836 | + .set_wol = rtl8152_set_wol, | |
20837 | + .get_strings = rtl8152_get_strings, | |
20838 | + .get_sset_count = rtl8152_get_sset_count, | |
20839 | + .get_ethtool_stats = rtl8152_get_ethtool_stats, | |
20840 | + .get_eee = rtl_ethtool_get_eee, | |
20841 | + .set_eee = rtl_ethtool_set_eee, | |
20842 | +}; | |
20843 | + | |
20844 | +static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
20845 | +{ | |
20846 | + struct r8152 *tp = netdev_priv(netdev); | |
20847 | + struct mii_ioctl_data *data = if_mii(rq); | |
20848 | + int res; | |
20849 | + | |
20850 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20851 | + return -ENODEV; | |
20852 | + | |
20853 | + res = usb_autopm_get_interface(tp->intf); | |
20854 | + if (res < 0) | |
20855 | + goto out; | |
20856 | + | |
20857 | + switch (cmd) { | |
20858 | + case SIOCGMIIPHY: | |
20859 | + data->phy_id = R8152_PHY_ID; /* Internal PHY */ | |
20860 | + break; | |
20861 | + | |
20862 | + case SIOCGMIIREG: | |
20863 | + mutex_lock(&tp->control); | |
20864 | + data->val_out = r8152_mdio_read(tp, data->reg_num); | |
20865 | + mutex_unlock(&tp->control); | |
20866 | + break; | |
20867 | + | |
20868 | + case SIOCSMIIREG: | |
20869 | + if (!capable(CAP_NET_ADMIN)) { | |
20870 | + res = -EPERM; | |
20871 | + break; | |
20872 | + } | |
20873 | + mutex_lock(&tp->control); | |
20874 | + r8152_mdio_write(tp, data->reg_num, data->val_in); | |
20875 | + mutex_unlock(&tp->control); | |
20876 | + break; | |
20877 | + | |
20878 | + default: | |
20879 | + res = -EOPNOTSUPP; | |
20880 | + } | |
20881 | + | |
20882 | + usb_autopm_put_interface(tp->intf); | |
20883 | + | |
20884 | +out: | |
20885 | + return res; | |
20886 | +} | |
20887 | + | |
20888 | +static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) | |
20889 | +{ | |
20890 | + struct r8152 *tp = netdev_priv(dev); | |
20891 | + | |
20892 | + switch (tp->version) { | |
20893 | + case RTL_VER_01: | |
20894 | + case RTL_VER_02: | |
20895 | + return eth_change_mtu(dev, new_mtu); | |
20896 | + default: | |
20897 | + break; | |
20898 | + } | |
20899 | + | |
20900 | + if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU) | |
20901 | + return -EINVAL; | |
20902 | + | |
20903 | + dev->mtu = new_mtu; | |
20904 | + | |
20905 | + return 0; | |
20906 | +} | |
20907 | + | |
20908 | +static const struct net_device_ops rtl8152_netdev_ops = { | |
20909 | + .ndo_open = rtl8152_open, | |
20910 | + .ndo_stop = rtl8152_close, | |
20911 | + .ndo_do_ioctl = rtl8152_ioctl, | |
20912 | + .ndo_start_xmit = rtl8152_start_xmit, | |
20913 | + .ndo_tx_timeout = rtl8152_tx_timeout, | |
20914 | + .ndo_set_features = rtl8152_set_features, | |
20915 | + .ndo_set_rx_mode = rtl8152_set_rx_mode, | |
20916 | + .ndo_set_mac_address = rtl8152_set_mac_address, | |
20917 | + .ndo_change_mtu = rtl8152_change_mtu, | |
20918 | + .ndo_validate_addr = eth_validate_addr, | |
20919 | +}; | |
20920 | + | |
20921 | +static void r8152b_get_version(struct r8152 *tp) | |
20922 | +{ | |
20923 | + u32 ocp_data; | |
20924 | + u16 version; | |
20925 | + | |
20926 | + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1); | |
20927 | + version = (u16)(ocp_data & VERSION_MASK); | |
20928 | + | |
20929 | + switch (version) { | |
20930 | + case 0x4c00: | |
20931 | + tp->version = RTL_VER_01; | |
20932 | + break; | |
20933 | + case 0x4c10: | |
20934 | + tp->version = RTL_VER_02; | |
20935 | + break; | |
20936 | + case 0x5c00: | |
20937 | + tp->version = RTL_VER_03; | |
20938 | + tp->mii.supports_gmii = 1; | |
20939 | + break; | |
20940 | + case 0x5c10: | |
20941 | + tp->version = RTL_VER_04; | |
20942 | + tp->mii.supports_gmii = 1; | |
20943 | + break; | |
20944 | + case 0x5c20: | |
20945 | + tp->version = RTL_VER_05; | |
20946 | + tp->mii.supports_gmii = 1; | |
20947 | + break; | |
20948 | + default: | |
20949 | + netif_info(tp, probe, tp->netdev, | |
20950 | + "Unknown version 0x%04x\n", version); | |
20951 | + break; | |
20952 | + } | |
20953 | +} | |
20954 | + | |
20955 | +static void rtl8152_unload(struct r8152 *tp) | |
20956 | +{ | |
20957 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20958 | + return; | |
20959 | + | |
20960 | + if (tp->version != RTL_VER_01) | |
20961 | + r8152_power_cut_en(tp, true); | |
20962 | +} | |
20963 | + | |
20964 | +static void rtl8153_unload(struct r8152 *tp) | |
20965 | +{ | |
20966 | + if (test_bit(RTL8152_UNPLUG, &tp->flags)) | |
20967 | + return; | |
20968 | + | |
20969 | + r8153_power_cut_en(tp, false); | |
20970 | +} | |
20971 | + | |
20972 | +static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) | |
20973 | +{ | |
20974 | + struct rtl_ops *ops = &tp->rtl_ops; | |
20975 | + int ret = -ENODEV; | |
20976 | + | |
20977 | + switch (id->idVendor) { | |
20978 | + case VENDOR_ID_REALTEK: | |
20979 | + switch (id->idProduct) { | |
20980 | + case PRODUCT_ID_RTL8152: | |
20981 | + ops->init = r8152b_init; | |
20982 | + ops->enable = rtl8152_enable; | |
20983 | + ops->disable = rtl8152_disable; | |
20984 | + ops->up = rtl8152_up; | |
20985 | + ops->down = rtl8152_down; | |
20986 | + ops->unload = rtl8152_unload; | |
20987 | + ops->eee_get = r8152_get_eee; | |
20988 | + ops->eee_set = r8152_set_eee; | |
20989 | + ret = 0; | |
20990 | + break; | |
20991 | + case PRODUCT_ID_RTL8153: | |
20992 | + ops->init = r8153_init; | |
20993 | + ops->enable = rtl8153_enable; | |
20994 | + ops->disable = rtl8153_disable; | |
20995 | + ops->up = rtl8153_up; | |
20996 | + ops->down = rtl8153_down; | |
20997 | + ops->unload = rtl8153_unload; | |
20998 | + ops->eee_get = r8153_get_eee; | |
20999 | + ops->eee_set = r8153_set_eee; | |
21000 | + ret = 0; | |
21001 | + break; | |
21002 | + default: | |
21003 | + break; | |
21004 | + } | |
21005 | + break; | |
21006 | + | |
21007 | + case VENDOR_ID_SAMSUNG: | |
21008 | + switch (id->idProduct) { | |
21009 | + case PRODUCT_ID_SAMSUNG: | |
21010 | + ops->init = r8153_init; | |
21011 | + ops->enable = rtl8153_enable; | |
21012 | + ops->disable = rtl8153_disable; | |
21013 | + ops->up = rtl8153_up; | |
21014 | + ops->down = rtl8153_down; | |
21015 | + ops->unload = rtl8153_unload; | |
21016 | + ops->eee_get = r8153_get_eee; | |
21017 | + ops->eee_set = r8153_set_eee; | |
21018 | + ret = 0; | |
21019 | + break; | |
21020 | + default: | |
21021 | + break; | |
21022 | + } | |
21023 | + break; | |
21024 | + | |
21025 | + default: | |
21026 | + break; | |
21027 | + } | |
21028 | + | |
21029 | + if (ret) | |
21030 | + netif_err(tp, probe, tp->netdev, "Unknown Device\n"); | |
21031 | + | |
21032 | + return ret; | |
21033 | +} | |
21034 | + | |
21035 | +static int rtl8152_probe(struct usb_interface *intf, | |
21036 | + const struct usb_device_id *id) | |
21037 | +{ | |
21038 | + struct usb_device *udev = interface_to_usbdev(intf); | |
21039 | + struct r8152 *tp; | |
21040 | + struct net_device *netdev; | |
21041 | + int ret; | |
21042 | + | |
21043 | + if (udev->actconfig->desc.bConfigurationValue != 1) { | |
21044 | + usb_driver_set_configuration(udev, 1); | |
21045 | + return -ENODEV; | |
21046 | + } | |
21047 | + | |
21048 | + usb_reset_device(udev); | |
21049 | + netdev = alloc_etherdev(sizeof(struct r8152)); | |
21050 | + if (!netdev) { | |
21051 | + dev_err(&intf->dev, "Out of memory\n"); | |
21052 | + return -ENOMEM; | |
21053 | + } | |
21054 | + | |
21055 | + SET_NETDEV_DEV(netdev, &intf->dev); | |
21056 | + tp = netdev_priv(netdev); | |
21057 | + tp->msg_enable = 0x7FFF; | |
21058 | + | |
21059 | + tp->udev = udev; | |
21060 | + tp->netdev = netdev; | |
21061 | + tp->intf = intf; | |
21062 | + | |
21063 | + ret = rtl_ops_init(tp, id); | |
21064 | + if (ret) | |
21065 | + goto out; | |
21066 | + | |
21067 | + tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); | |
21068 | + mutex_init(&tp->control); | |
21069 | + INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); | |
21070 | + | |
21071 | + netdev->netdev_ops = &rtl8152_netdev_ops; | |
21072 | + netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; | |
21073 | + | |
21074 | + netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | | |
21075 | + NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | | |
21076 | + NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_RX | | |
21077 | + NETIF_F_HW_VLAN_CTAG_TX; | |
21078 | + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | | |
21079 | + NETIF_F_TSO | NETIF_F_FRAGLIST | | |
21080 | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | | |
21081 | + NETIF_F_HW_VLAN_CTAG_RX | | |
21082 | + NETIF_F_HW_VLAN_CTAG_TX; | |
21083 | + netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | | |
21084 | + NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | | |
21085 | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6; | |
21086 | + | |
21087 | + netdev->ethtool_ops = &ops; | |
21088 | + netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); | |
21089 | + | |
21090 | + tp->mii.dev = netdev; | |
21091 | + tp->mii.mdio_read = read_mii_word; | |
21092 | + tp->mii.mdio_write = write_mii_word; | |
21093 | + tp->mii.phy_id_mask = 0x3f; | |
21094 | + tp->mii.reg_num_mask = 0x1f; | |
21095 | + tp->mii.phy_id = R8152_PHY_ID; | |
21096 | + tp->mii.supports_gmii = 0; | |
21097 | + | |
21098 | + intf->needs_remote_wakeup = 1; | |
21099 | + | |
21100 | + r8152b_get_version(tp); | |
21101 | + tp->rtl_ops.init(tp); | |
21102 | + set_ethernet_addr(tp); | |
21103 | + | |
21104 | + usb_set_intfdata(intf, tp); | |
21105 | + | |
21106 | + ret = register_netdev(netdev); | |
21107 | + if (ret != 0) { | |
21108 | + netif_err(tp, probe, netdev, "couldn't register the device\n"); | |
21109 | + goto out1; | |
21110 | + } | |
21111 | + | |
21112 | + tp->saved_wolopts = __rtl_get_wol(tp); | |
21113 | + if (tp->saved_wolopts) | |
21114 | + device_set_wakeup_enable(&udev->dev, true); | |
21115 | + else | |
21116 | + device_set_wakeup_enable(&udev->dev, false); | |
21117 | + | |
21118 | + netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); | |
21119 | + | |
21120 | + return 0; | |
21121 | + | |
21122 | +out1: | |
21123 | + usb_set_intfdata(intf, NULL); | |
21124 | +out: | |
21125 | + free_netdev(netdev); | |
21126 | + return ret; | |
21127 | +} | |
21128 | + | |
21129 | +static void rtl8152_disconnect(struct usb_interface *intf) | |
21130 | +{ | |
21131 | + struct r8152 *tp = usb_get_intfdata(intf); | |
21132 | + | |
21133 | + usb_set_intfdata(intf, NULL); | |
21134 | + if (tp) { | |
21135 | + struct usb_device *udev = tp->udev; | |
21136 | + | |
21137 | + if (udev->state == USB_STATE_NOTATTACHED) | |
21138 | + set_bit(RTL8152_UNPLUG, &tp->flags); | |
21139 | + | |
21140 | + tasklet_kill(&tp->tl); | |
21141 | + unregister_netdev(tp->netdev); | |
21142 | + tp->rtl_ops.unload(tp); | |
21143 | + free_netdev(tp->netdev); | |
21144 | + } | |
21145 | +} | |
21146 | + | |
21147 | +/* table of devices that work with this driver */ | |
21148 | +static struct usb_device_id rtl8152_table[] = { | |
21149 | + {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, | |
21150 | + {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, | |
21151 | + {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, | |
21152 | + {} | |
21153 | +}; | |
21154 | + | |
21155 | +MODULE_DEVICE_TABLE(usb, rtl8152_table); | |
21156 | + | |
21157 | +static struct usb_driver rtl8152_driver = { | |
21158 | + .name = MODULENAME, | |
21159 | + .id_table = rtl8152_table, | |
21160 | + .probe = rtl8152_probe, | |
21161 | + .disconnect = rtl8152_disconnect, | |
21162 | + .suspend = rtl8152_suspend, | |
21163 | + .resume = rtl8152_resume, | |
21164 | + .reset_resume = rtl8152_resume, | |
21165 | + .supports_autosuspend = 1, | |
21166 | + .disable_hub_initiated_lpm = 1, | |
21167 | +}; | |
21168 | + | |
21169 | +module_usb_driver(rtl8152_driver); | |
21170 | + | |
21171 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
21172 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
21173 | +MODULE_LICENSE("GPL"); | |
21174 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/rtl8150.c backports-3.18.1-1/drivers/net/usb/rtl8150.c | |
21175 | --- backports-3.18.1-1.org/drivers/net/usb/rtl8150.c 1970-01-01 01:00:00.000000000 +0100 | |
21176 | +++ backports-3.18.1-1/drivers/net/usb/rtl8150.c 2014-12-16 18:39:45.000000000 +0100 | |
21177 | @@ -0,0 +1,950 @@ | |
21178 | +/* | |
21179 | + * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) | |
21180 | + * | |
21181 | + * This program is free software; you can redistribute it and/or | |
21182 | + * modify it under the terms of the GNU General Public License | |
21183 | + * version 2 as published by the Free Software Foundation. | |
21184 | + */ | |
21185 | + | |
21186 | +#include <linux/signal.h> | |
21187 | +#include <linux/slab.h> | |
21188 | +#include <linux/module.h> | |
21189 | +#include <linux/netdevice.h> | |
21190 | +#include <linux/etherdevice.h> | |
21191 | +#include <linux/mii.h> | |
21192 | +#include <linux/ethtool.h> | |
21193 | +#include <linux/usb.h> | |
21194 | +#include <asm/uaccess.h> | |
21195 | + | |
21196 | +/* Version Information */ | |
21197 | +#define DRIVER_VERSION "v0.6.2 (2004/08/27)" | |
21198 | +#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" | |
21199 | +#define DRIVER_DESC "rtl8150 based usb-ethernet driver" | |
21200 | + | |
21201 | +#define IDR 0x0120 | |
21202 | +#define MAR 0x0126 | |
21203 | +#define CR 0x012e | |
21204 | +#define TCR 0x012f | |
21205 | +#define RCR 0x0130 | |
21206 | +#define TSR 0x0132 | |
21207 | +#define RSR 0x0133 | |
21208 | +#define CON0 0x0135 | |
21209 | +#define CON1 0x0136 | |
21210 | +#define MSR 0x0137 | |
21211 | +#define PHYADD 0x0138 | |
21212 | +#define PHYDAT 0x0139 | |
21213 | +#define PHYCNT 0x013b | |
21214 | +#define GPPC 0x013d | |
21215 | +#define BMCR 0x0140 | |
21216 | +#define BMSR 0x0142 | |
21217 | +#define ANAR 0x0144 | |
21218 | +#define ANLP 0x0146 | |
21219 | +#define AER 0x0148 | |
21220 | +#define CSCR 0x014C /* This one has the link status */ | |
21221 | +#define CSCR_LINK_STATUS (1 << 3) | |
21222 | + | |
21223 | +#define IDR_EEPROM 0x1202 | |
21224 | + | |
21225 | +#define PHY_READ 0 | |
21226 | +#define PHY_WRITE 0x20 | |
21227 | +#define PHY_GO 0x40 | |
21228 | + | |
21229 | +#define MII_TIMEOUT 10 | |
21230 | +#define INTBUFSIZE 8 | |
21231 | + | |
21232 | +#define RTL8150_REQT_READ 0xc0 | |
21233 | +#define RTL8150_REQT_WRITE 0x40 | |
21234 | +#define RTL8150_REQ_GET_REGS 0x05 | |
21235 | +#define RTL8150_REQ_SET_REGS 0x05 | |
21236 | + | |
21237 | + | |
21238 | +/* Transmit status register errors */ | |
21239 | +#define TSR_ECOL (1<<5) | |
21240 | +#define TSR_LCOL (1<<4) | |
21241 | +#define TSR_LOSS_CRS (1<<3) | |
21242 | +#define TSR_JBR (1<<2) | |
21243 | +#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) | |
21244 | +/* Receive status register errors */ | |
21245 | +#define RSR_CRC (1<<2) | |
21246 | +#define RSR_FAE (1<<1) | |
21247 | +#define RSR_ERRORS (RSR_CRC | RSR_FAE) | |
21248 | + | |
21249 | +/* Media status register definitions */ | |
21250 | +#define MSR_DUPLEX (1<<4) | |
21251 | +#define MSR_SPEED (1<<3) | |
21252 | +#define MSR_LINK (1<<2) | |
21253 | + | |
21254 | +/* Interrupt pipe data */ | |
21255 | +#define INT_TSR 0x00 | |
21256 | +#define INT_RSR 0x01 | |
21257 | +#define INT_MSR 0x02 | |
21258 | +#define INT_WAKSR 0x03 | |
21259 | +#define INT_TXOK_CNT 0x04 | |
21260 | +#define INT_RXLOST_CNT 0x05 | |
21261 | +#define INT_CRERR_CNT 0x06 | |
21262 | +#define INT_COL_CNT 0x07 | |
21263 | + | |
21264 | + | |
21265 | +#define RTL8150_MTU 1540 | |
21266 | +#define RTL8150_TX_TIMEOUT (HZ) | |
21267 | +#define RX_SKB_POOL_SIZE 4 | |
21268 | + | |
21269 | +/* rtl8150 flags */ | |
21270 | +#define RTL8150_HW_CRC 0 | |
21271 | +#define RX_REG_SET 1 | |
21272 | +#define RTL8150_UNPLUG 2 | |
21273 | +#define RX_URB_FAIL 3 | |
21274 | + | |
21275 | +/* Define these values to match your device */ | |
21276 | +#define VENDOR_ID_REALTEK 0x0bda | |
21277 | +#define VENDOR_ID_MELCO 0x0411 | |
21278 | +#define VENDOR_ID_MICRONET 0x3980 | |
21279 | +#define VENDOR_ID_LONGSHINE 0x07b8 | |
21280 | +#define VENDOR_ID_OQO 0x1557 | |
21281 | +#define VENDOR_ID_ZYXEL 0x0586 | |
21282 | + | |
21283 | +#define PRODUCT_ID_RTL8150 0x8150 | |
21284 | +#define PRODUCT_ID_LUAKTX 0x0012 | |
21285 | +#define PRODUCT_ID_LCS8138TX 0x401a | |
21286 | +#define PRODUCT_ID_SP128AR 0x0003 | |
21287 | +#define PRODUCT_ID_PRESTIGE 0x401a | |
21288 | + | |
21289 | +#undef EEPROM_WRITE | |
21290 | + | |
21291 | +/* table of devices that work with this driver */ | |
21292 | +static struct usb_device_id rtl8150_table[] = { | |
21293 | + {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, | |
21294 | + {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, | |
21295 | + {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, | |
21296 | + {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, | |
21297 | + {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)}, | |
21298 | + {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)}, | |
21299 | + {} | |
21300 | +}; | |
21301 | + | |
21302 | +MODULE_DEVICE_TABLE(usb, rtl8150_table); | |
21303 | + | |
21304 | +struct rtl8150 { | |
21305 | + unsigned long flags; | |
21306 | + struct usb_device *udev; | |
21307 | + struct tasklet_struct tl; | |
21308 | + struct net_device *netdev; | |
21309 | + struct urb *rx_urb, *tx_urb, *intr_urb; | |
21310 | + struct sk_buff *tx_skb, *rx_skb; | |
21311 | + struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE]; | |
21312 | + spinlock_t rx_pool_lock; | |
21313 | + struct usb_ctrlrequest dr; | |
21314 | + int intr_interval; | |
21315 | + u8 *intr_buff; | |
21316 | + u8 phy; | |
21317 | +}; | |
21318 | + | |
21319 | +typedef struct rtl8150 rtl8150_t; | |
21320 | + | |
21321 | +struct async_req { | |
21322 | + struct usb_ctrlrequest dr; | |
21323 | + u16 rx_creg; | |
21324 | +}; | |
21325 | + | |
21326 | +static const char driver_name [] = "rtl8150"; | |
21327 | + | |
21328 | +/* | |
21329 | +** | |
21330 | +** device related part of the code | |
21331 | +** | |
21332 | +*/ | |
21333 | +static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) | |
21334 | +{ | |
21335 | + return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), | |
21336 | + RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, | |
21337 | + indx, 0, data, size, 500); | |
21338 | +} | |
21339 | + | |
21340 | +static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) | |
21341 | +{ | |
21342 | + return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), | |
21343 | + RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, | |
21344 | + indx, 0, data, size, 500); | |
21345 | +} | |
21346 | + | |
21347 | +static void async_set_reg_cb(struct urb *urb) | |
21348 | +{ | |
21349 | + struct async_req *req = (struct async_req *)urb->context; | |
21350 | + int status = urb->status; | |
21351 | + | |
21352 | + if (status < 0) | |
21353 | + dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); | |
21354 | + kfree(req); | |
21355 | + usb_free_urb(urb); | |
21356 | +} | |
21357 | + | |
21358 | +static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg) | |
21359 | +{ | |
21360 | + int res = -ENOMEM; | |
21361 | + struct urb *async_urb; | |
21362 | + struct async_req *req; | |
21363 | + | |
21364 | + req = kmalloc(sizeof(struct async_req), GFP_ATOMIC); | |
21365 | + if (req == NULL) | |
21366 | + return res; | |
21367 | + async_urb = usb_alloc_urb(0, GFP_ATOMIC); | |
21368 | + if (async_urb == NULL) { | |
21369 | + kfree(req); | |
21370 | + return res; | |
21371 | + } | |
21372 | + req->rx_creg = cpu_to_le16(reg); | |
21373 | + req->dr.bRequestType = RTL8150_REQT_WRITE; | |
21374 | + req->dr.bRequest = RTL8150_REQ_SET_REGS; | |
21375 | + req->dr.wIndex = 0; | |
21376 | + req->dr.wValue = cpu_to_le16(indx); | |
21377 | + req->dr.wLength = cpu_to_le16(size); | |
21378 | + usb_fill_control_urb(async_urb, dev->udev, | |
21379 | + usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr, | |
21380 | + &req->rx_creg, size, async_set_reg_cb, req); | |
21381 | + res = usb_submit_urb(async_urb, GFP_ATOMIC); | |
21382 | + if (res) { | |
21383 | + if (res == -ENODEV) | |
21384 | + netif_device_detach(dev->netdev); | |
21385 | + dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res); | |
21386 | + } | |
21387 | + return res; | |
21388 | +} | |
21389 | + | |
21390 | +static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg) | |
21391 | +{ | |
21392 | + int i; | |
21393 | + u8 data[3], tmp; | |
21394 | + | |
21395 | + data[0] = phy; | |
21396 | + data[1] = data[2] = 0; | |
21397 | + tmp = indx | PHY_READ | PHY_GO; | |
21398 | + i = 0; | |
21399 | + | |
21400 | + set_registers(dev, PHYADD, sizeof(data), data); | |
21401 | + set_registers(dev, PHYCNT, 1, &tmp); | |
21402 | + do { | |
21403 | + get_registers(dev, PHYCNT, 1, data); | |
21404 | + } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); | |
21405 | + | |
21406 | + if (i <= MII_TIMEOUT) { | |
21407 | + get_registers(dev, PHYDAT, 2, data); | |
21408 | + *reg = data[0] | (data[1] << 8); | |
21409 | + return 0; | |
21410 | + } else | |
21411 | + return 1; | |
21412 | +} | |
21413 | + | |
21414 | +static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg) | |
21415 | +{ | |
21416 | + int i; | |
21417 | + u8 data[3], tmp; | |
21418 | + | |
21419 | + data[0] = phy; | |
21420 | + data[1] = reg & 0xff; | |
21421 | + data[2] = (reg >> 8) & 0xff; | |
21422 | + tmp = indx | PHY_WRITE | PHY_GO; | |
21423 | + i = 0; | |
21424 | + | |
21425 | + set_registers(dev, PHYADD, sizeof(data), data); | |
21426 | + set_registers(dev, PHYCNT, 1, &tmp); | |
21427 | + do { | |
21428 | + get_registers(dev, PHYCNT, 1, data); | |
21429 | + } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT)); | |
21430 | + | |
21431 | + if (i <= MII_TIMEOUT) | |
21432 | + return 0; | |
21433 | + else | |
21434 | + return 1; | |
21435 | +} | |
21436 | + | |
21437 | +static inline void set_ethernet_addr(rtl8150_t * dev) | |
21438 | +{ | |
21439 | + u8 node_id[6]; | |
21440 | + | |
21441 | + get_registers(dev, IDR, sizeof(node_id), node_id); | |
21442 | + memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id)); | |
21443 | +} | |
21444 | + | |
21445 | +static int rtl8150_set_mac_address(struct net_device *netdev, void *p) | |
21446 | +{ | |
21447 | + struct sockaddr *addr = p; | |
21448 | + rtl8150_t *dev = netdev_priv(netdev); | |
21449 | + | |
21450 | + if (netif_running(netdev)) | |
21451 | + return -EBUSY; | |
21452 | + | |
21453 | + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | |
21454 | + netdev_dbg(netdev, "Setting MAC address to %pM\n", netdev->dev_addr); | |
21455 | + /* Set the IDR registers. */ | |
21456 | + set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr); | |
21457 | +#ifdef EEPROM_WRITE | |
21458 | + { | |
21459 | + int i; | |
21460 | + u8 cr; | |
21461 | + /* Get the CR contents. */ | |
21462 | + get_registers(dev, CR, 1, &cr); | |
21463 | + /* Set the WEPROM bit (eeprom write enable). */ | |
21464 | + cr |= 0x20; | |
21465 | + set_registers(dev, CR, 1, &cr); | |
21466 | + /* Write the MAC address into eeprom. Eeprom writes must be word-sized, | |
21467 | + so we need to split them up. */ | |
21468 | + for (i = 0; i * 2 < netdev->addr_len; i++) { | |
21469 | + set_registers(dev, IDR_EEPROM + (i * 2), 2, | |
21470 | + netdev->dev_addr + (i * 2)); | |
21471 | + } | |
21472 | + /* Clear the WEPROM bit (preventing accidental eeprom writes). */ | |
21473 | + cr &= 0xdf; | |
21474 | + set_registers(dev, CR, 1, &cr); | |
21475 | + } | |
21476 | +#endif | |
21477 | + return 0; | |
21478 | +} | |
21479 | + | |
21480 | +static int rtl8150_reset(rtl8150_t * dev) | |
21481 | +{ | |
21482 | + u8 data = 0x10; | |
21483 | + int i = HZ; | |
21484 | + | |
21485 | + set_registers(dev, CR, 1, &data); | |
21486 | + do { | |
21487 | + get_registers(dev, CR, 1, &data); | |
21488 | + } while ((data & 0x10) && --i); | |
21489 | + | |
21490 | + return (i > 0) ? 1 : 0; | |
21491 | +} | |
21492 | + | |
21493 | +static int alloc_all_urbs(rtl8150_t * dev) | |
21494 | +{ | |
21495 | + dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
21496 | + if (!dev->rx_urb) | |
21497 | + return 0; | |
21498 | + dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
21499 | + if (!dev->tx_urb) { | |
21500 | + usb_free_urb(dev->rx_urb); | |
21501 | + return 0; | |
21502 | + } | |
21503 | + dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); | |
21504 | + if (!dev->intr_urb) { | |
21505 | + usb_free_urb(dev->rx_urb); | |
21506 | + usb_free_urb(dev->tx_urb); | |
21507 | + return 0; | |
21508 | + } | |
21509 | + | |
21510 | + return 1; | |
21511 | +} | |
21512 | + | |
21513 | +static void free_all_urbs(rtl8150_t * dev) | |
21514 | +{ | |
21515 | + usb_free_urb(dev->rx_urb); | |
21516 | + usb_free_urb(dev->tx_urb); | |
21517 | + usb_free_urb(dev->intr_urb); | |
21518 | +} | |
21519 | + | |
21520 | +static void unlink_all_urbs(rtl8150_t * dev) | |
21521 | +{ | |
21522 | + usb_kill_urb(dev->rx_urb); | |
21523 | + usb_kill_urb(dev->tx_urb); | |
21524 | + usb_kill_urb(dev->intr_urb); | |
21525 | +} | |
21526 | + | |
21527 | +static inline struct sk_buff *pull_skb(rtl8150_t *dev) | |
21528 | +{ | |
21529 | + struct sk_buff *skb; | |
21530 | + int i; | |
21531 | + | |
21532 | + for (i = 0; i < RX_SKB_POOL_SIZE; i++) { | |
21533 | + if (dev->rx_skb_pool[i]) { | |
21534 | + skb = dev->rx_skb_pool[i]; | |
21535 | + dev->rx_skb_pool[i] = NULL; | |
21536 | + return skb; | |
21537 | + } | |
21538 | + } | |
21539 | + return NULL; | |
21540 | +} | |
21541 | + | |
21542 | +static void read_bulk_callback(struct urb *urb) | |
21543 | +{ | |
21544 | + rtl8150_t *dev; | |
21545 | + unsigned pkt_len, res; | |
21546 | + struct sk_buff *skb; | |
21547 | + struct net_device *netdev; | |
21548 | + u16 rx_stat; | |
21549 | + int status = urb->status; | |
21550 | + int result; | |
21551 | + | |
21552 | + dev = urb->context; | |
21553 | + if (!dev) | |
21554 | + return; | |
21555 | + if (test_bit(RTL8150_UNPLUG, &dev->flags)) | |
21556 | + return; | |
21557 | + netdev = dev->netdev; | |
21558 | + if (!netif_device_present(netdev)) | |
21559 | + return; | |
21560 | + | |
21561 | + switch (status) { | |
21562 | + case 0: | |
21563 | + break; | |
21564 | + case -ENOENT: | |
21565 | + return; /* the urb is in unlink state */ | |
21566 | + case -ETIME: | |
21567 | + if (printk_ratelimit()) | |
21568 | + dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); | |
21569 | + goto goon; | |
21570 | + default: | |
21571 | + if (printk_ratelimit()) | |
21572 | + dev_warn(&urb->dev->dev, "Rx status %d\n", status); | |
21573 | + goto goon; | |
21574 | + } | |
21575 | + | |
21576 | + if (!dev->rx_skb) | |
21577 | + goto resched; | |
21578 | + /* protect against short packets (tell me why we got some?!?) */ | |
21579 | + if (urb->actual_length < 4) | |
21580 | + goto goon; | |
21581 | + | |
21582 | + res = urb->actual_length; | |
21583 | + rx_stat = le16_to_cpu(*(__le16 *)(urb->transfer_buffer + res - 4)); | |
21584 | + pkt_len = res - 4; | |
21585 | + | |
21586 | + skb_put(dev->rx_skb, pkt_len); | |
21587 | + dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev); | |
21588 | + netif_rx(dev->rx_skb); | |
21589 | + netdev->stats.rx_packets++; | |
21590 | + netdev->stats.rx_bytes += pkt_len; | |
21591 | + | |
21592 | + spin_lock(&dev->rx_pool_lock); | |
21593 | + skb = pull_skb(dev); | |
21594 | + spin_unlock(&dev->rx_pool_lock); | |
21595 | + if (!skb) | |
21596 | + goto resched; | |
21597 | + | |
21598 | + dev->rx_skb = skb; | |
21599 | +goon: | |
21600 | + usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | |
21601 | + dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | |
21602 | + result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); | |
21603 | + if (result == -ENODEV) | |
21604 | + netif_device_detach(dev->netdev); | |
21605 | + else if (result) { | |
21606 | + set_bit(RX_URB_FAIL, &dev->flags); | |
21607 | + goto resched; | |
21608 | + } else { | |
21609 | + clear_bit(RX_URB_FAIL, &dev->flags); | |
21610 | + } | |
21611 | + | |
21612 | + return; | |
21613 | +resched: | |
21614 | + tasklet_schedule(&dev->tl); | |
21615 | +} | |
21616 | + | |
21617 | +static void write_bulk_callback(struct urb *urb) | |
21618 | +{ | |
21619 | + rtl8150_t *dev; | |
21620 | + int status = urb->status; | |
21621 | + | |
21622 | + dev = urb->context; | |
21623 | + if (!dev) | |
21624 | + return; | |
21625 | + dev_kfree_skb_irq(dev->tx_skb); | |
21626 | + if (!netif_device_present(dev->netdev)) | |
21627 | + return; | |
21628 | + if (status) | |
21629 | + dev_info(&urb->dev->dev, "%s: Tx status %d\n", | |
21630 | + dev->netdev->name, status); | |
21631 | + dev->netdev->trans_start = jiffies; | |
21632 | + netif_wake_queue(dev->netdev); | |
21633 | +} | |
21634 | + | |
21635 | +static void intr_callback(struct urb *urb) | |
21636 | +{ | |
21637 | + rtl8150_t *dev; | |
21638 | + __u8 *d; | |
21639 | + int status = urb->status; | |
21640 | + int res; | |
21641 | + | |
21642 | + dev = urb->context; | |
21643 | + if (!dev) | |
21644 | + return; | |
21645 | + switch (status) { | |
21646 | + case 0: /* success */ | |
21647 | + break; | |
21648 | + case -ECONNRESET: /* unlink */ | |
21649 | + case -ENOENT: | |
21650 | + case -ESHUTDOWN: | |
21651 | + return; | |
21652 | + /* -EPIPE: should clear the halt */ | |
21653 | + default: | |
21654 | + dev_info(&urb->dev->dev, "%s: intr status %d\n", | |
21655 | + dev->netdev->name, status); | |
21656 | + goto resubmit; | |
21657 | + } | |
21658 | + | |
21659 | + d = urb->transfer_buffer; | |
21660 | + if (d[0] & TSR_ERRORS) { | |
21661 | + dev->netdev->stats.tx_errors++; | |
21662 | + if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) | |
21663 | + dev->netdev->stats.tx_aborted_errors++; | |
21664 | + if (d[INT_TSR] & TSR_LCOL) | |
21665 | + dev->netdev->stats.tx_window_errors++; | |
21666 | + if (d[INT_TSR] & TSR_LOSS_CRS) | |
21667 | + dev->netdev->stats.tx_carrier_errors++; | |
21668 | + } | |
21669 | + /* Report link status changes to the network stack */ | |
21670 | + if ((d[INT_MSR] & MSR_LINK) == 0) { | |
21671 | + if (netif_carrier_ok(dev->netdev)) { | |
21672 | + netif_carrier_off(dev->netdev); | |
21673 | + netdev_dbg(dev->netdev, "%s: LINK LOST\n", __func__); | |
21674 | + } | |
21675 | + } else { | |
21676 | + if (!netif_carrier_ok(dev->netdev)) { | |
21677 | + netif_carrier_on(dev->netdev); | |
21678 | + netdev_dbg(dev->netdev, "%s: LINK CAME BACK\n", __func__); | |
21679 | + } | |
21680 | + } | |
21681 | + | |
21682 | +resubmit: | |
21683 | + res = usb_submit_urb (urb, GFP_ATOMIC); | |
21684 | + if (res == -ENODEV) | |
21685 | + netif_device_detach(dev->netdev); | |
21686 | + else if (res) | |
21687 | + dev_err(&dev->udev->dev, | |
21688 | + "can't resubmit intr, %s-%s/input0, status %d\n", | |
21689 | + dev->udev->bus->bus_name, dev->udev->devpath, res); | |
21690 | +} | |
21691 | + | |
21692 | +static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) | |
21693 | +{ | |
21694 | + rtl8150_t *dev = usb_get_intfdata(intf); | |
21695 | + | |
21696 | + netif_device_detach(dev->netdev); | |
21697 | + | |
21698 | + if (netif_running(dev->netdev)) { | |
21699 | + usb_kill_urb(dev->rx_urb); | |
21700 | + usb_kill_urb(dev->intr_urb); | |
21701 | + } | |
21702 | + return 0; | |
21703 | +} | |
21704 | + | |
21705 | +static int rtl8150_resume(struct usb_interface *intf) | |
21706 | +{ | |
21707 | + rtl8150_t *dev = usb_get_intfdata(intf); | |
21708 | + | |
21709 | + netif_device_attach(dev->netdev); | |
21710 | + if (netif_running(dev->netdev)) { | |
21711 | + dev->rx_urb->status = 0; | |
21712 | + dev->rx_urb->actual_length = 0; | |
21713 | + read_bulk_callback(dev->rx_urb); | |
21714 | + | |
21715 | + dev->intr_urb->status = 0; | |
21716 | + dev->intr_urb->actual_length = 0; | |
21717 | + intr_callback(dev->intr_urb); | |
21718 | + } | |
21719 | + return 0; | |
21720 | +} | |
21721 | + | |
21722 | +/* | |
21723 | +** | |
21724 | +** network related part of the code | |
21725 | +** | |
21726 | +*/ | |
21727 | + | |
21728 | +static void fill_skb_pool(rtl8150_t *dev) | |
21729 | +{ | |
21730 | + struct sk_buff *skb; | |
21731 | + int i; | |
21732 | + | |
21733 | + for (i = 0; i < RX_SKB_POOL_SIZE; i++) { | |
21734 | + if (dev->rx_skb_pool[i]) | |
21735 | + continue; | |
21736 | + skb = dev_alloc_skb(RTL8150_MTU + 2); | |
21737 | + if (!skb) { | |
21738 | + return; | |
21739 | + } | |
21740 | + skb_reserve(skb, 2); | |
21741 | + dev->rx_skb_pool[i] = skb; | |
21742 | + } | |
21743 | +} | |
21744 | + | |
21745 | +static void free_skb_pool(rtl8150_t *dev) | |
21746 | +{ | |
21747 | + int i; | |
21748 | + | |
21749 | + for (i = 0; i < RX_SKB_POOL_SIZE; i++) | |
21750 | + if (dev->rx_skb_pool[i]) | |
21751 | + dev_kfree_skb(dev->rx_skb_pool[i]); | |
21752 | +} | |
21753 | + | |
21754 | +static void rx_fixup(unsigned long data) | |
21755 | +{ | |
21756 | + struct rtl8150 *dev = (struct rtl8150 *)data; | |
21757 | + struct sk_buff *skb; | |
21758 | + int status; | |
21759 | + | |
21760 | + spin_lock_irq(&dev->rx_pool_lock); | |
21761 | + fill_skb_pool(dev); | |
21762 | + spin_unlock_irq(&dev->rx_pool_lock); | |
21763 | + if (test_bit(RX_URB_FAIL, &dev->flags)) | |
21764 | + if (dev->rx_skb) | |
21765 | + goto try_again; | |
21766 | + spin_lock_irq(&dev->rx_pool_lock); | |
21767 | + skb = pull_skb(dev); | |
21768 | + spin_unlock_irq(&dev->rx_pool_lock); | |
21769 | + if (skb == NULL) | |
21770 | + goto tlsched; | |
21771 | + dev->rx_skb = skb; | |
21772 | + usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | |
21773 | + dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | |
21774 | +try_again: | |
21775 | + status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); | |
21776 | + if (status == -ENODEV) { | |
21777 | + netif_device_detach(dev->netdev); | |
21778 | + } else if (status) { | |
21779 | + set_bit(RX_URB_FAIL, &dev->flags); | |
21780 | + goto tlsched; | |
21781 | + } else { | |
21782 | + clear_bit(RX_URB_FAIL, &dev->flags); | |
21783 | + } | |
21784 | + | |
21785 | + return; | |
21786 | +tlsched: | |
21787 | + tasklet_schedule(&dev->tl); | |
21788 | +} | |
21789 | + | |
21790 | +static int enable_net_traffic(rtl8150_t * dev) | |
21791 | +{ | |
21792 | + u8 cr, tcr, rcr, msr; | |
21793 | + | |
21794 | + if (!rtl8150_reset(dev)) { | |
21795 | + dev_warn(&dev->udev->dev, "device reset failed\n"); | |
21796 | + } | |
21797 | + /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ | |
21798 | + rcr = 0x9e; | |
21799 | + tcr = 0xd8; | |
21800 | + cr = 0x0c; | |
21801 | + if (!(rcr & 0x80)) | |
21802 | + set_bit(RTL8150_HW_CRC, &dev->flags); | |
21803 | + set_registers(dev, RCR, 1, &rcr); | |
21804 | + set_registers(dev, TCR, 1, &tcr); | |
21805 | + set_registers(dev, CR, 1, &cr); | |
21806 | + get_registers(dev, MSR, 1, &msr); | |
21807 | + | |
21808 | + return 0; | |
21809 | +} | |
21810 | + | |
21811 | +static void disable_net_traffic(rtl8150_t * dev) | |
21812 | +{ | |
21813 | + u8 cr; | |
21814 | + | |
21815 | + get_registers(dev, CR, 1, &cr); | |
21816 | + cr &= 0xf3; | |
21817 | + set_registers(dev, CR, 1, &cr); | |
21818 | +} | |
21819 | + | |
21820 | +static void rtl8150_tx_timeout(struct net_device *netdev) | |
21821 | +{ | |
21822 | + rtl8150_t *dev = netdev_priv(netdev); | |
21823 | + dev_warn(&netdev->dev, "Tx timeout.\n"); | |
21824 | + usb_unlink_urb(dev->tx_urb); | |
21825 | + netdev->stats.tx_errors++; | |
21826 | +} | |
21827 | + | |
21828 | +static void rtl8150_set_multicast(struct net_device *netdev) | |
21829 | +{ | |
21830 | + rtl8150_t *dev = netdev_priv(netdev); | |
21831 | + u16 rx_creg = 0x9e; | |
21832 | + | |
21833 | + netif_stop_queue(netdev); | |
21834 | + if (netdev->flags & IFF_PROMISC) { | |
21835 | + rx_creg |= 0x0001; | |
21836 | + dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); | |
21837 | + } else if (!netdev_mc_empty(netdev) || | |
21838 | + (netdev->flags & IFF_ALLMULTI)) { | |
21839 | + rx_creg &= 0xfffe; | |
21840 | + rx_creg |= 0x0002; | |
21841 | + dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); | |
21842 | + } else { | |
21843 | + /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ | |
21844 | + rx_creg &= 0x00fc; | |
21845 | + } | |
21846 | + async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg); | |
21847 | + netif_wake_queue(netdev); | |
21848 | +} | |
21849 | + | |
21850 | +static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, | |
21851 | + struct net_device *netdev) | |
21852 | +{ | |
21853 | + rtl8150_t *dev = netdev_priv(netdev); | |
21854 | + int count, res; | |
21855 | + | |
21856 | + netif_stop_queue(netdev); | |
21857 | + count = (skb->len < 60) ? 60 : skb->len; | |
21858 | + count = (count & 0x3f) ? count : count + 1; | |
21859 | + dev->tx_skb = skb; | |
21860 | + usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), | |
21861 | + skb->data, count, write_bulk_callback, dev); | |
21862 | + if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) { | |
21863 | + /* Can we get/handle EPIPE here? */ | |
21864 | + if (res == -ENODEV) | |
21865 | + netif_device_detach(dev->netdev); | |
21866 | + else { | |
21867 | + dev_warn(&netdev->dev, "failed tx_urb %d\n", res); | |
21868 | + netdev->stats.tx_errors++; | |
21869 | + netif_start_queue(netdev); | |
21870 | + } | |
21871 | + } else { | |
21872 | + netdev->stats.tx_packets++; | |
21873 | + netdev->stats.tx_bytes += skb->len; | |
21874 | + netdev->trans_start = jiffies; | |
21875 | + } | |
21876 | + | |
21877 | + return NETDEV_TX_OK; | |
21878 | +} | |
21879 | + | |
21880 | + | |
21881 | +static void set_carrier(struct net_device *netdev) | |
21882 | +{ | |
21883 | + rtl8150_t *dev = netdev_priv(netdev); | |
21884 | + short tmp; | |
21885 | + | |
21886 | + get_registers(dev, CSCR, 2, &tmp); | |
21887 | + if (tmp & CSCR_LINK_STATUS) | |
21888 | + netif_carrier_on(netdev); | |
21889 | + else | |
21890 | + netif_carrier_off(netdev); | |
21891 | +} | |
21892 | + | |
21893 | +static int rtl8150_open(struct net_device *netdev) | |
21894 | +{ | |
21895 | + rtl8150_t *dev = netdev_priv(netdev); | |
21896 | + int res; | |
21897 | + | |
21898 | + if (dev->rx_skb == NULL) | |
21899 | + dev->rx_skb = pull_skb(dev); | |
21900 | + if (!dev->rx_skb) | |
21901 | + return -ENOMEM; | |
21902 | + | |
21903 | + set_registers(dev, IDR, 6, netdev->dev_addr); | |
21904 | + | |
21905 | + usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), | |
21906 | + dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); | |
21907 | + if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) { | |
21908 | + if (res == -ENODEV) | |
21909 | + netif_device_detach(dev->netdev); | |
21910 | + dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res); | |
21911 | + return res; | |
21912 | + } | |
21913 | + usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), | |
21914 | + dev->intr_buff, INTBUFSIZE, intr_callback, | |
21915 | + dev, dev->intr_interval); | |
21916 | + if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) { | |
21917 | + if (res == -ENODEV) | |
21918 | + netif_device_detach(dev->netdev); | |
21919 | + dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res); | |
21920 | + usb_kill_urb(dev->rx_urb); | |
21921 | + return res; | |
21922 | + } | |
21923 | + enable_net_traffic(dev); | |
21924 | + set_carrier(netdev); | |
21925 | + netif_start_queue(netdev); | |
21926 | + | |
21927 | + return res; | |
21928 | +} | |
21929 | + | |
21930 | +static int rtl8150_close(struct net_device *netdev) | |
21931 | +{ | |
21932 | + rtl8150_t *dev = netdev_priv(netdev); | |
21933 | + int res = 0; | |
21934 | + | |
21935 | + netif_stop_queue(netdev); | |
21936 | + if (!test_bit(RTL8150_UNPLUG, &dev->flags)) | |
21937 | + disable_net_traffic(dev); | |
21938 | + unlink_all_urbs(dev); | |
21939 | + | |
21940 | + return res; | |
21941 | +} | |
21942 | + | |
21943 | +static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) | |
21944 | +{ | |
21945 | + rtl8150_t *dev = netdev_priv(netdev); | |
21946 | + | |
21947 | + strlcpy(info->driver, driver_name, sizeof(info->driver)); | |
21948 | + strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
21949 | + usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); | |
21950 | +} | |
21951 | + | |
21952 | +static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |
21953 | +{ | |
21954 | + rtl8150_t *dev = netdev_priv(netdev); | |
21955 | + short lpa, bmcr; | |
21956 | + | |
21957 | + ecmd->supported = (SUPPORTED_10baseT_Half | | |
21958 | + SUPPORTED_10baseT_Full | | |
21959 | + SUPPORTED_100baseT_Half | | |
21960 | + SUPPORTED_100baseT_Full | | |
21961 | + SUPPORTED_Autoneg | | |
21962 | + SUPPORTED_TP | SUPPORTED_MII); | |
21963 | + ecmd->port = PORT_TP; | |
21964 | + ecmd->transceiver = XCVR_INTERNAL; | |
21965 | + ecmd->phy_address = dev->phy; | |
21966 | + get_registers(dev, BMCR, 2, &bmcr); | |
21967 | + get_registers(dev, ANLP, 2, &lpa); | |
21968 | + if (bmcr & BMCR_ANENABLE) { | |
21969 | + u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ? | |
21970 | + SPEED_100 : SPEED_10); | |
21971 | + ethtool_cmd_speed_set(ecmd, speed); | |
21972 | + ecmd->autoneg = AUTONEG_ENABLE; | |
21973 | + if (speed == SPEED_100) | |
21974 | + ecmd->duplex = (lpa & LPA_100FULL) ? | |
21975 | + DUPLEX_FULL : DUPLEX_HALF; | |
21976 | + else | |
21977 | + ecmd->duplex = (lpa & LPA_10FULL) ? | |
21978 | + DUPLEX_FULL : DUPLEX_HALF; | |
21979 | + } else { | |
21980 | + ecmd->autoneg = AUTONEG_DISABLE; | |
21981 | + ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ? | |
21982 | + SPEED_100 : SPEED_10)); | |
21983 | + ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? | |
21984 | + DUPLEX_FULL : DUPLEX_HALF; | |
21985 | + } | |
21986 | + return 0; | |
21987 | +} | |
21988 | + | |
21989 | +static const struct ethtool_ops ops = { | |
21990 | + .get_drvinfo = rtl8150_get_drvinfo, | |
21991 | + .get_settings = rtl8150_get_settings, | |
21992 | + .get_link = ethtool_op_get_link | |
21993 | +}; | |
21994 | + | |
21995 | +static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
21996 | +{ | |
21997 | + rtl8150_t *dev = netdev_priv(netdev); | |
21998 | + u16 *data = (u16 *) & rq->ifr_ifru; | |
21999 | + int res = 0; | |
22000 | + | |
22001 | + switch (cmd) { | |
22002 | + case SIOCDEVPRIVATE: | |
22003 | + data[0] = dev->phy; | |
22004 | + case SIOCDEVPRIVATE + 1: | |
22005 | + read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]); | |
22006 | + break; | |
22007 | + case SIOCDEVPRIVATE + 2: | |
22008 | + if (!capable(CAP_NET_ADMIN)) | |
22009 | + return -EPERM; | |
22010 | + write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]); | |
22011 | + break; | |
22012 | + default: | |
22013 | + res = -EOPNOTSUPP; | |
22014 | + } | |
22015 | + | |
22016 | + return res; | |
22017 | +} | |
22018 | + | |
22019 | +static const struct net_device_ops rtl8150_netdev_ops = { | |
22020 | + .ndo_open = rtl8150_open, | |
22021 | + .ndo_stop = rtl8150_close, | |
22022 | + .ndo_do_ioctl = rtl8150_ioctl, | |
22023 | + .ndo_start_xmit = rtl8150_start_xmit, | |
22024 | + .ndo_tx_timeout = rtl8150_tx_timeout, | |
22025 | + .ndo_set_rx_mode = rtl8150_set_multicast, | |
22026 | + .ndo_set_mac_address = rtl8150_set_mac_address, | |
22027 | + | |
22028 | + .ndo_change_mtu = eth_change_mtu, | |
22029 | + .ndo_validate_addr = eth_validate_addr, | |
22030 | +}; | |
22031 | + | |
22032 | +static int rtl8150_probe(struct usb_interface *intf, | |
22033 | + const struct usb_device_id *id) | |
22034 | +{ | |
22035 | + struct usb_device *udev = interface_to_usbdev(intf); | |
22036 | + rtl8150_t *dev; | |
22037 | + struct net_device *netdev; | |
22038 | + | |
22039 | + netdev = alloc_etherdev(sizeof(rtl8150_t)); | |
22040 | + if (!netdev) | |
22041 | + return -ENOMEM; | |
22042 | + | |
22043 | + dev = netdev_priv(netdev); | |
22044 | + | |
22045 | + dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL); | |
22046 | + if (!dev->intr_buff) { | |
22047 | + free_netdev(netdev); | |
22048 | + return -ENOMEM; | |
22049 | + } | |
22050 | + | |
22051 | + tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev); | |
22052 | + spin_lock_init(&dev->rx_pool_lock); | |
22053 | + | |
22054 | + dev->udev = udev; | |
22055 | + dev->netdev = netdev; | |
22056 | + netdev->netdev_ops = &rtl8150_netdev_ops; | |
22057 | + netdev->watchdog_timeo = RTL8150_TX_TIMEOUT; | |
22058 | + netdev->ethtool_ops = &ops; | |
22059 | + dev->intr_interval = 100; /* 100ms */ | |
22060 | + | |
22061 | + if (!alloc_all_urbs(dev)) { | |
22062 | + dev_err(&intf->dev, "out of memory\n"); | |
22063 | + goto out; | |
22064 | + } | |
22065 | + if (!rtl8150_reset(dev)) { | |
22066 | + dev_err(&intf->dev, "couldn't reset the device\n"); | |
22067 | + goto out1; | |
22068 | + } | |
22069 | + fill_skb_pool(dev); | |
22070 | + set_ethernet_addr(dev); | |
22071 | + | |
22072 | + usb_set_intfdata(intf, dev); | |
22073 | + SET_NETDEV_DEV(netdev, &intf->dev); | |
22074 | + if (register_netdev(netdev) != 0) { | |
22075 | + dev_err(&intf->dev, "couldn't register the device\n"); | |
22076 | + goto out2; | |
22077 | + } | |
22078 | + | |
22079 | + dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name); | |
22080 | + | |
22081 | + return 0; | |
22082 | + | |
22083 | +out2: | |
22084 | + usb_set_intfdata(intf, NULL); | |
22085 | + free_skb_pool(dev); | |
22086 | +out1: | |
22087 | + free_all_urbs(dev); | |
22088 | +out: | |
22089 | + kfree(dev->intr_buff); | |
22090 | + free_netdev(netdev); | |
22091 | + return -EIO; | |
22092 | +} | |
22093 | + | |
22094 | +static void rtl8150_disconnect(struct usb_interface *intf) | |
22095 | +{ | |
22096 | + rtl8150_t *dev = usb_get_intfdata(intf); | |
22097 | + | |
22098 | + usb_set_intfdata(intf, NULL); | |
22099 | + if (dev) { | |
22100 | + set_bit(RTL8150_UNPLUG, &dev->flags); | |
22101 | + tasklet_kill(&dev->tl); | |
22102 | + unregister_netdev(dev->netdev); | |
22103 | + unlink_all_urbs(dev); | |
22104 | + free_all_urbs(dev); | |
22105 | + free_skb_pool(dev); | |
22106 | + if (dev->rx_skb) | |
22107 | + dev_kfree_skb(dev->rx_skb); | |
22108 | + kfree(dev->intr_buff); | |
22109 | + free_netdev(dev->netdev); | |
22110 | + } | |
22111 | +} | |
22112 | + | |
22113 | +static struct usb_driver rtl8150_driver = { | |
22114 | + .name = driver_name, | |
22115 | + .probe = rtl8150_probe, | |
22116 | + .disconnect = rtl8150_disconnect, | |
22117 | + .id_table = rtl8150_table, | |
22118 | + .suspend = rtl8150_suspend, | |
22119 | + .resume = rtl8150_resume, | |
22120 | + .disable_hub_initiated_lpm = 1, | |
22121 | +}; | |
22122 | + | |
22123 | +module_usb_driver(rtl8150_driver); | |
22124 | + | |
22125 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
22126 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
22127 | +MODULE_LICENSE("GPL"); | |
22128 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/smsc75xx.c backports-3.18.1-1/drivers/net/usb/smsc75xx.c | |
22129 | --- backports-3.18.1-1.org/drivers/net/usb/smsc75xx.c 1970-01-01 01:00:00.000000000 +0100 | |
22130 | +++ backports-3.18.1-1/drivers/net/usb/smsc75xx.c 2014-12-16 18:39:45.000000000 +0100 | |
22131 | @@ -0,0 +1,2286 @@ | |
22132 | + /*************************************************************************** | |
22133 | + * | |
22134 | + * Copyright (C) 2007-2010 SMSC | |
22135 | + * | |
22136 | + * This program is free software; you can redistribute it and/or | |
22137 | + * modify it under the terms of the GNU General Public License | |
22138 | + * as published by the Free Software Foundation; either version 2 | |
22139 | + * of the License, or (at your option) any later version. | |
22140 | + * | |
22141 | + * This program is distributed in the hope that it will be useful, | |
22142 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22143 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22144 | + * GNU General Public License for more details. | |
22145 | + * | |
22146 | + * You should have received a copy of the GNU General Public License | |
22147 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
22148 | + * | |
22149 | + *****************************************************************************/ | |
22150 | + | |
22151 | +#include <linux/module.h> | |
22152 | +#include <linux/kmod.h> | |
22153 | +#include <linux/netdevice.h> | |
22154 | +#include <linux/etherdevice.h> | |
22155 | +#include <linux/ethtool.h> | |
22156 | +#include <linux/mii.h> | |
22157 | +#include <linux/usb.h> | |
22158 | +#include <linux/bitrev.h> | |
22159 | +#include <linux/crc16.h> | |
22160 | +#include <linux/crc32.h> | |
22161 | +#include <linux/usb/usbnet.h> | |
22162 | +#include <linux/slab.h> | |
22163 | +#include "smsc75xx.h" | |
22164 | + | |
22165 | +#define SMSC_CHIPNAME "smsc75xx" | |
22166 | +#define SMSC_DRIVER_VERSION "1.0.0" | |
22167 | +#define HS_USB_PKT_SIZE (512) | |
22168 | +#define FS_USB_PKT_SIZE (64) | |
22169 | +#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) | |
22170 | +#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) | |
22171 | +#define DEFAULT_BULK_IN_DELAY (0x00002000) | |
22172 | +#define MAX_SINGLE_PACKET_SIZE (9000) | |
22173 | +#define LAN75XX_EEPROM_MAGIC (0x7500) | |
22174 | +#define EEPROM_MAC_OFFSET (0x01) | |
22175 | +#define DEFAULT_TX_CSUM_ENABLE (true) | |
22176 | +#define DEFAULT_RX_CSUM_ENABLE (true) | |
22177 | +#define SMSC75XX_INTERNAL_PHY_ID (1) | |
22178 | +#define SMSC75XX_TX_OVERHEAD (8) | |
22179 | +#define MAX_RX_FIFO_SIZE (20 * 1024) | |
22180 | +#define MAX_TX_FIFO_SIZE (12 * 1024) | |
22181 | +#define USB_VENDOR_ID_SMSC (0x0424) | |
22182 | +#define USB_PRODUCT_ID_LAN7500 (0x7500) | |
22183 | +#define USB_PRODUCT_ID_LAN7505 (0x7505) | |
22184 | +#define RXW_PADDING 2 | |
22185 | +#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \ | |
22186 | + WAKE_MCAST | WAKE_ARP | WAKE_MAGIC) | |
22187 | + | |
22188 | +#define SUSPEND_SUSPEND0 (0x01) | |
22189 | +#define SUSPEND_SUSPEND1 (0x02) | |
22190 | +#define SUSPEND_SUSPEND2 (0x04) | |
22191 | +#define SUSPEND_SUSPEND3 (0x08) | |
22192 | +#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \ | |
22193 | + SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3) | |
22194 | + | |
22195 | +struct smsc75xx_priv { | |
22196 | + struct usbnet *dev; | |
22197 | + u32 rfe_ctl; | |
22198 | + u32 wolopts; | |
22199 | + u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; | |
22200 | + struct mutex dataport_mutex; | |
22201 | + spinlock_t rfe_ctl_lock; | |
22202 | + struct work_struct set_multicast; | |
22203 | + u8 suspend_flags; | |
22204 | +}; | |
22205 | + | |
22206 | +struct usb_context { | |
22207 | + struct usb_ctrlrequest req; | |
22208 | + struct usbnet *dev; | |
22209 | +}; | |
22210 | + | |
22211 | +static bool turbo_mode = true; | |
22212 | +module_param(turbo_mode, bool, 0644); | |
22213 | +MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); | |
22214 | + | |
22215 | +static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, | |
22216 | + u32 *data, int in_pm) | |
22217 | +{ | |
22218 | + u32 buf; | |
22219 | + int ret; | |
22220 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); | |
22221 | + | |
22222 | + BUG_ON(!dev); | |
22223 | + | |
22224 | + if (!in_pm) | |
22225 | + fn = usbnet_read_cmd; | |
22226 | + else | |
22227 | + fn = usbnet_read_cmd_nopm; | |
22228 | + | |
22229 | + ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN | |
22230 | + | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
22231 | + 0, index, &buf, 4); | |
22232 | + if (unlikely(ret < 0)) | |
22233 | + netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", | |
22234 | + index, ret); | |
22235 | + | |
22236 | + le32_to_cpus(&buf); | |
22237 | + *data = buf; | |
22238 | + | |
22239 | + return ret; | |
22240 | +} | |
22241 | + | |
22242 | +static int __must_check __smsc75xx_write_reg(struct usbnet *dev, u32 index, | |
22243 | + u32 data, int in_pm) | |
22244 | +{ | |
22245 | + u32 buf; | |
22246 | + int ret; | |
22247 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16); | |
22248 | + | |
22249 | + BUG_ON(!dev); | |
22250 | + | |
22251 | + if (!in_pm) | |
22252 | + fn = usbnet_write_cmd; | |
22253 | + else | |
22254 | + fn = usbnet_write_cmd_nopm; | |
22255 | + | |
22256 | + buf = data; | |
22257 | + cpu_to_le32s(&buf); | |
22258 | + | |
22259 | + ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT | |
22260 | + | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
22261 | + 0, index, &buf, 4); | |
22262 | + if (unlikely(ret < 0)) | |
22263 | + netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n", | |
22264 | + index, ret); | |
22265 | + | |
22266 | + return ret; | |
22267 | +} | |
22268 | + | |
22269 | +static int __must_check smsc75xx_read_reg_nopm(struct usbnet *dev, u32 index, | |
22270 | + u32 *data) | |
22271 | +{ | |
22272 | + return __smsc75xx_read_reg(dev, index, data, 1); | |
22273 | +} | |
22274 | + | |
22275 | +static int __must_check smsc75xx_write_reg_nopm(struct usbnet *dev, u32 index, | |
22276 | + u32 data) | |
22277 | +{ | |
22278 | + return __smsc75xx_write_reg(dev, index, data, 1); | |
22279 | +} | |
22280 | + | |
22281 | +static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, | |
22282 | + u32 *data) | |
22283 | +{ | |
22284 | + return __smsc75xx_read_reg(dev, index, data, 0); | |
22285 | +} | |
22286 | + | |
22287 | +static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, | |
22288 | + u32 data) | |
22289 | +{ | |
22290 | + return __smsc75xx_write_reg(dev, index, data, 0); | |
22291 | +} | |
22292 | + | |
22293 | +/* Loop until the read is completed with timeout | |
22294 | + * called with phy_mutex held */ | |
22295 | +static __must_check int __smsc75xx_phy_wait_not_busy(struct usbnet *dev, | |
22296 | + int in_pm) | |
22297 | +{ | |
22298 | + unsigned long start_time = jiffies; | |
22299 | + u32 val; | |
22300 | + int ret; | |
22301 | + | |
22302 | + do { | |
22303 | + ret = __smsc75xx_read_reg(dev, MII_ACCESS, &val, in_pm); | |
22304 | + if (ret < 0) { | |
22305 | + netdev_warn(dev->net, "Error reading MII_ACCESS\n"); | |
22306 | + return ret; | |
22307 | + } | |
22308 | + | |
22309 | + if (!(val & MII_ACCESS_BUSY)) | |
22310 | + return 0; | |
22311 | + } while (!time_after(jiffies, start_time + HZ)); | |
22312 | + | |
22313 | + return -EIO; | |
22314 | +} | |
22315 | + | |
22316 | +static int __smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx, | |
22317 | + int in_pm) | |
22318 | +{ | |
22319 | + struct usbnet *dev = netdev_priv(netdev); | |
22320 | + u32 val, addr; | |
22321 | + int ret; | |
22322 | + | |
22323 | + mutex_lock(&dev->phy_mutex); | |
22324 | + | |
22325 | + /* confirm MII not busy */ | |
22326 | + ret = __smsc75xx_phy_wait_not_busy(dev, in_pm); | |
22327 | + if (ret < 0) { | |
22328 | + netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_read\n"); | |
22329 | + goto done; | |
22330 | + } | |
22331 | + | |
22332 | + /* set the address, index & direction (read from PHY) */ | |
22333 | + phy_id &= dev->mii.phy_id_mask; | |
22334 | + idx &= dev->mii.reg_num_mask; | |
22335 | + addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | |
22336 | + | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) | |
22337 | + | MII_ACCESS_READ | MII_ACCESS_BUSY; | |
22338 | + ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm); | |
22339 | + if (ret < 0) { | |
22340 | + netdev_warn(dev->net, "Error writing MII_ACCESS\n"); | |
22341 | + goto done; | |
22342 | + } | |
22343 | + | |
22344 | + ret = __smsc75xx_phy_wait_not_busy(dev, in_pm); | |
22345 | + if (ret < 0) { | |
22346 | + netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx); | |
22347 | + goto done; | |
22348 | + } | |
22349 | + | |
22350 | + ret = __smsc75xx_read_reg(dev, MII_DATA, &val, in_pm); | |
22351 | + if (ret < 0) { | |
22352 | + netdev_warn(dev->net, "Error reading MII_DATA\n"); | |
22353 | + goto done; | |
22354 | + } | |
22355 | + | |
22356 | + ret = (u16)(val & 0xFFFF); | |
22357 | + | |
22358 | +done: | |
22359 | + mutex_unlock(&dev->phy_mutex); | |
22360 | + return ret; | |
22361 | +} | |
22362 | + | |
22363 | +static void __smsc75xx_mdio_write(struct net_device *netdev, int phy_id, | |
22364 | + int idx, int regval, int in_pm) | |
22365 | +{ | |
22366 | + struct usbnet *dev = netdev_priv(netdev); | |
22367 | + u32 val, addr; | |
22368 | + int ret; | |
22369 | + | |
22370 | + mutex_lock(&dev->phy_mutex); | |
22371 | + | |
22372 | + /* confirm MII not busy */ | |
22373 | + ret = __smsc75xx_phy_wait_not_busy(dev, in_pm); | |
22374 | + if (ret < 0) { | |
22375 | + netdev_warn(dev->net, "MII is busy in smsc75xx_mdio_write\n"); | |
22376 | + goto done; | |
22377 | + } | |
22378 | + | |
22379 | + val = regval; | |
22380 | + ret = __smsc75xx_write_reg(dev, MII_DATA, val, in_pm); | |
22381 | + if (ret < 0) { | |
22382 | + netdev_warn(dev->net, "Error writing MII_DATA\n"); | |
22383 | + goto done; | |
22384 | + } | |
22385 | + | |
22386 | + /* set the address, index & direction (write to PHY) */ | |
22387 | + phy_id &= dev->mii.phy_id_mask; | |
22388 | + idx &= dev->mii.reg_num_mask; | |
22389 | + addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | |
22390 | + | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) | |
22391 | + | MII_ACCESS_WRITE | MII_ACCESS_BUSY; | |
22392 | + ret = __smsc75xx_write_reg(dev, MII_ACCESS, addr, in_pm); | |
22393 | + if (ret < 0) { | |
22394 | + netdev_warn(dev->net, "Error writing MII_ACCESS\n"); | |
22395 | + goto done; | |
22396 | + } | |
22397 | + | |
22398 | + ret = __smsc75xx_phy_wait_not_busy(dev, in_pm); | |
22399 | + if (ret < 0) { | |
22400 | + netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx); | |
22401 | + goto done; | |
22402 | + } | |
22403 | + | |
22404 | +done: | |
22405 | + mutex_unlock(&dev->phy_mutex); | |
22406 | +} | |
22407 | + | |
22408 | +static int smsc75xx_mdio_read_nopm(struct net_device *netdev, int phy_id, | |
22409 | + int idx) | |
22410 | +{ | |
22411 | + return __smsc75xx_mdio_read(netdev, phy_id, idx, 1); | |
22412 | +} | |
22413 | + | |
22414 | +static void smsc75xx_mdio_write_nopm(struct net_device *netdev, int phy_id, | |
22415 | + int idx, int regval) | |
22416 | +{ | |
22417 | + __smsc75xx_mdio_write(netdev, phy_id, idx, regval, 1); | |
22418 | +} | |
22419 | + | |
22420 | +static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) | |
22421 | +{ | |
22422 | + return __smsc75xx_mdio_read(netdev, phy_id, idx, 0); | |
22423 | +} | |
22424 | + | |
22425 | +static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, | |
22426 | + int regval) | |
22427 | +{ | |
22428 | + __smsc75xx_mdio_write(netdev, phy_id, idx, regval, 0); | |
22429 | +} | |
22430 | + | |
22431 | +static int smsc75xx_wait_eeprom(struct usbnet *dev) | |
22432 | +{ | |
22433 | + unsigned long start_time = jiffies; | |
22434 | + u32 val; | |
22435 | + int ret; | |
22436 | + | |
22437 | + do { | |
22438 | + ret = smsc75xx_read_reg(dev, E2P_CMD, &val); | |
22439 | + if (ret < 0) { | |
22440 | + netdev_warn(dev->net, "Error reading E2P_CMD\n"); | |
22441 | + return ret; | |
22442 | + } | |
22443 | + | |
22444 | + if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT)) | |
22445 | + break; | |
22446 | + udelay(40); | |
22447 | + } while (!time_after(jiffies, start_time + HZ)); | |
22448 | + | |
22449 | + if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) { | |
22450 | + netdev_warn(dev->net, "EEPROM read operation timeout\n"); | |
22451 | + return -EIO; | |
22452 | + } | |
22453 | + | |
22454 | + return 0; | |
22455 | +} | |
22456 | + | |
22457 | +static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev) | |
22458 | +{ | |
22459 | + unsigned long start_time = jiffies; | |
22460 | + u32 val; | |
22461 | + int ret; | |
22462 | + | |
22463 | + do { | |
22464 | + ret = smsc75xx_read_reg(dev, E2P_CMD, &val); | |
22465 | + if (ret < 0) { | |
22466 | + netdev_warn(dev->net, "Error reading E2P_CMD\n"); | |
22467 | + return ret; | |
22468 | + } | |
22469 | + | |
22470 | + if (!(val & E2P_CMD_BUSY)) | |
22471 | + return 0; | |
22472 | + | |
22473 | + udelay(40); | |
22474 | + } while (!time_after(jiffies, start_time + HZ)); | |
22475 | + | |
22476 | + netdev_warn(dev->net, "EEPROM is busy\n"); | |
22477 | + return -EIO; | |
22478 | +} | |
22479 | + | |
22480 | +static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, | |
22481 | + u8 *data) | |
22482 | +{ | |
22483 | + u32 val; | |
22484 | + int i, ret; | |
22485 | + | |
22486 | + BUG_ON(!dev); | |
22487 | + BUG_ON(!data); | |
22488 | + | |
22489 | + ret = smsc75xx_eeprom_confirm_not_busy(dev); | |
22490 | + if (ret) | |
22491 | + return ret; | |
22492 | + | |
22493 | + for (i = 0; i < length; i++) { | |
22494 | + val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR); | |
22495 | + ret = smsc75xx_write_reg(dev, E2P_CMD, val); | |
22496 | + if (ret < 0) { | |
22497 | + netdev_warn(dev->net, "Error writing E2P_CMD\n"); | |
22498 | + return ret; | |
22499 | + } | |
22500 | + | |
22501 | + ret = smsc75xx_wait_eeprom(dev); | |
22502 | + if (ret < 0) | |
22503 | + return ret; | |
22504 | + | |
22505 | + ret = smsc75xx_read_reg(dev, E2P_DATA, &val); | |
22506 | + if (ret < 0) { | |
22507 | + netdev_warn(dev->net, "Error reading E2P_DATA\n"); | |
22508 | + return ret; | |
22509 | + } | |
22510 | + | |
22511 | + data[i] = val & 0xFF; | |
22512 | + offset++; | |
22513 | + } | |
22514 | + | |
22515 | + return 0; | |
22516 | +} | |
22517 | + | |
22518 | +static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, | |
22519 | + u8 *data) | |
22520 | +{ | |
22521 | + u32 val; | |
22522 | + int i, ret; | |
22523 | + | |
22524 | + BUG_ON(!dev); | |
22525 | + BUG_ON(!data); | |
22526 | + | |
22527 | + ret = smsc75xx_eeprom_confirm_not_busy(dev); | |
22528 | + if (ret) | |
22529 | + return ret; | |
22530 | + | |
22531 | + /* Issue write/erase enable command */ | |
22532 | + val = E2P_CMD_BUSY | E2P_CMD_EWEN; | |
22533 | + ret = smsc75xx_write_reg(dev, E2P_CMD, val); | |
22534 | + if (ret < 0) { | |
22535 | + netdev_warn(dev->net, "Error writing E2P_CMD\n"); | |
22536 | + return ret; | |
22537 | + } | |
22538 | + | |
22539 | + ret = smsc75xx_wait_eeprom(dev); | |
22540 | + if (ret < 0) | |
22541 | + return ret; | |
22542 | + | |
22543 | + for (i = 0; i < length; i++) { | |
22544 | + | |
22545 | + /* Fill data register */ | |
22546 | + val = data[i]; | |
22547 | + ret = smsc75xx_write_reg(dev, E2P_DATA, val); | |
22548 | + if (ret < 0) { | |
22549 | + netdev_warn(dev->net, "Error writing E2P_DATA\n"); | |
22550 | + return ret; | |
22551 | + } | |
22552 | + | |
22553 | + /* Send "write" command */ | |
22554 | + val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR); | |
22555 | + ret = smsc75xx_write_reg(dev, E2P_CMD, val); | |
22556 | + if (ret < 0) { | |
22557 | + netdev_warn(dev->net, "Error writing E2P_CMD\n"); | |
22558 | + return ret; | |
22559 | + } | |
22560 | + | |
22561 | + ret = smsc75xx_wait_eeprom(dev); | |
22562 | + if (ret < 0) | |
22563 | + return ret; | |
22564 | + | |
22565 | + offset++; | |
22566 | + } | |
22567 | + | |
22568 | + return 0; | |
22569 | +} | |
22570 | + | |
22571 | +static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev) | |
22572 | +{ | |
22573 | + int i, ret; | |
22574 | + | |
22575 | + for (i = 0; i < 100; i++) { | |
22576 | + u32 dp_sel; | |
22577 | + ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); | |
22578 | + if (ret < 0) { | |
22579 | + netdev_warn(dev->net, "Error reading DP_SEL\n"); | |
22580 | + return ret; | |
22581 | + } | |
22582 | + | |
22583 | + if (dp_sel & DP_SEL_DPRDY) | |
22584 | + return 0; | |
22585 | + | |
22586 | + udelay(40); | |
22587 | + } | |
22588 | + | |
22589 | + netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out\n"); | |
22590 | + | |
22591 | + return -EIO; | |
22592 | +} | |
22593 | + | |
22594 | +static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr, | |
22595 | + u32 length, u32 *buf) | |
22596 | +{ | |
22597 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
22598 | + u32 dp_sel; | |
22599 | + int i, ret; | |
22600 | + | |
22601 | + mutex_lock(&pdata->dataport_mutex); | |
22602 | + | |
22603 | + ret = smsc75xx_dataport_wait_not_busy(dev); | |
22604 | + if (ret < 0) { | |
22605 | + netdev_warn(dev->net, "smsc75xx_dataport_write busy on entry\n"); | |
22606 | + goto done; | |
22607 | + } | |
22608 | + | |
22609 | + ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); | |
22610 | + if (ret < 0) { | |
22611 | + netdev_warn(dev->net, "Error reading DP_SEL\n"); | |
22612 | + goto done; | |
22613 | + } | |
22614 | + | |
22615 | + dp_sel &= ~DP_SEL_RSEL; | |
22616 | + dp_sel |= ram_select; | |
22617 | + ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel); | |
22618 | + if (ret < 0) { | |
22619 | + netdev_warn(dev->net, "Error writing DP_SEL\n"); | |
22620 | + goto done; | |
22621 | + } | |
22622 | + | |
22623 | + for (i = 0; i < length; i++) { | |
22624 | + ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i); | |
22625 | + if (ret < 0) { | |
22626 | + netdev_warn(dev->net, "Error writing DP_ADDR\n"); | |
22627 | + goto done; | |
22628 | + } | |
22629 | + | |
22630 | + ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]); | |
22631 | + if (ret < 0) { | |
22632 | + netdev_warn(dev->net, "Error writing DP_DATA\n"); | |
22633 | + goto done; | |
22634 | + } | |
22635 | + | |
22636 | + ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE); | |
22637 | + if (ret < 0) { | |
22638 | + netdev_warn(dev->net, "Error writing DP_CMD\n"); | |
22639 | + goto done; | |
22640 | + } | |
22641 | + | |
22642 | + ret = smsc75xx_dataport_wait_not_busy(dev); | |
22643 | + if (ret < 0) { | |
22644 | + netdev_warn(dev->net, "smsc75xx_dataport_write timeout\n"); | |
22645 | + goto done; | |
22646 | + } | |
22647 | + } | |
22648 | + | |
22649 | +done: | |
22650 | + mutex_unlock(&pdata->dataport_mutex); | |
22651 | + return ret; | |
22652 | +} | |
22653 | + | |
22654 | +/* returns hash bit number for given MAC address */ | |
22655 | +static u32 smsc75xx_hash(char addr[ETH_ALEN]) | |
22656 | +{ | |
22657 | + return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; | |
22658 | +} | |
22659 | + | |
22660 | +static void smsc75xx_deferred_multicast_write(struct work_struct *param) | |
22661 | +{ | |
22662 | + struct smsc75xx_priv *pdata = | |
22663 | + container_of(param, struct smsc75xx_priv, set_multicast); | |
22664 | + struct usbnet *dev = pdata->dev; | |
22665 | + int ret; | |
22666 | + | |
22667 | + netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n", | |
22668 | + pdata->rfe_ctl); | |
22669 | + | |
22670 | + smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN, | |
22671 | + DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table); | |
22672 | + | |
22673 | + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | |
22674 | + if (ret < 0) | |
22675 | + netdev_warn(dev->net, "Error writing RFE_CRL\n"); | |
22676 | +} | |
22677 | + | |
22678 | +static void smsc75xx_set_multicast(struct net_device *netdev) | |
22679 | +{ | |
22680 | + struct usbnet *dev = netdev_priv(netdev); | |
22681 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
22682 | + unsigned long flags; | |
22683 | + int i; | |
22684 | + | |
22685 | + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | |
22686 | + | |
22687 | + pdata->rfe_ctl &= | |
22688 | + ~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF); | |
22689 | + pdata->rfe_ctl |= RFE_CTL_AB; | |
22690 | + | |
22691 | + for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) | |
22692 | + pdata->multicast_hash_table[i] = 0; | |
22693 | + | |
22694 | + if (dev->net->flags & IFF_PROMISC) { | |
22695 | + netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n"); | |
22696 | + pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU; | |
22697 | + } else if (dev->net->flags & IFF_ALLMULTI) { | |
22698 | + netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n"); | |
22699 | + pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF; | |
22700 | + } else if (!netdev_mc_empty(dev->net)) { | |
22701 | + struct netdev_hw_addr *ha; | |
22702 | + | |
22703 | + netif_dbg(dev, drv, dev->net, "receive multicast hash filter\n"); | |
22704 | + | |
22705 | + pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF; | |
22706 | + | |
22707 | + netdev_for_each_mc_addr(ha, netdev) { | |
22708 | + u32 bitnum = smsc75xx_hash(ha->addr); | |
22709 | + pdata->multicast_hash_table[bitnum / 32] |= | |
22710 | + (1 << (bitnum % 32)); | |
22711 | + } | |
22712 | + } else { | |
22713 | + netif_dbg(dev, drv, dev->net, "receive own packets only\n"); | |
22714 | + pdata->rfe_ctl |= RFE_CTL_DPF; | |
22715 | + } | |
22716 | + | |
22717 | + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | |
22718 | + | |
22719 | + /* defer register writes to a sleepable context */ | |
22720 | + schedule_work(&pdata->set_multicast); | |
22721 | +} | |
22722 | + | |
22723 | +static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, | |
22724 | + u16 lcladv, u16 rmtadv) | |
22725 | +{ | |
22726 | + u32 flow = 0, fct_flow = 0; | |
22727 | + int ret; | |
22728 | + | |
22729 | + if (duplex == DUPLEX_FULL) { | |
22730 | + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); | |
22731 | + | |
22732 | + if (cap & FLOW_CTRL_TX) { | |
22733 | + flow = (FLOW_TX_FCEN | 0xFFFF); | |
22734 | + /* set fct_flow thresholds to 20% and 80% */ | |
22735 | + fct_flow = (8 << 8) | 32; | |
22736 | + } | |
22737 | + | |
22738 | + if (cap & FLOW_CTRL_RX) | |
22739 | + flow |= FLOW_RX_FCEN; | |
22740 | + | |
22741 | + netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n", | |
22742 | + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), | |
22743 | + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); | |
22744 | + } else { | |
22745 | + netif_dbg(dev, link, dev->net, "half duplex\n"); | |
22746 | + } | |
22747 | + | |
22748 | + ret = smsc75xx_write_reg(dev, FLOW, flow); | |
22749 | + if (ret < 0) { | |
22750 | + netdev_warn(dev->net, "Error writing FLOW\n"); | |
22751 | + return ret; | |
22752 | + } | |
22753 | + | |
22754 | + ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow); | |
22755 | + if (ret < 0) { | |
22756 | + netdev_warn(dev->net, "Error writing FCT_FLOW\n"); | |
22757 | + return ret; | |
22758 | + } | |
22759 | + | |
22760 | + return 0; | |
22761 | +} | |
22762 | + | |
22763 | +static int smsc75xx_link_reset(struct usbnet *dev) | |
22764 | +{ | |
22765 | + struct mii_if_info *mii = &dev->mii; | |
22766 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
22767 | + u16 lcladv, rmtadv; | |
22768 | + int ret; | |
22769 | + | |
22770 | + /* write to clear phy interrupt status */ | |
22771 | + smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, | |
22772 | + PHY_INT_SRC_CLEAR_ALL); | |
22773 | + | |
22774 | + ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); | |
22775 | + if (ret < 0) { | |
22776 | + netdev_warn(dev->net, "Error writing INT_STS\n"); | |
22777 | + return ret; | |
22778 | + } | |
22779 | + | |
22780 | + mii_check_media(mii, 1, 1); | |
22781 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
22782 | + lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); | |
22783 | + rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); | |
22784 | + | |
22785 | + netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", | |
22786 | + ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); | |
22787 | + | |
22788 | + return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); | |
22789 | +} | |
22790 | + | |
22791 | +static void smsc75xx_status(struct usbnet *dev, struct urb *urb) | |
22792 | +{ | |
22793 | + u32 intdata; | |
22794 | + | |
22795 | + if (urb->actual_length != 4) { | |
22796 | + netdev_warn(dev->net, "unexpected urb length %d\n", | |
22797 | + urb->actual_length); | |
22798 | + return; | |
22799 | + } | |
22800 | + | |
22801 | + memcpy(&intdata, urb->transfer_buffer, 4); | |
22802 | + le32_to_cpus(&intdata); | |
22803 | + | |
22804 | + netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata); | |
22805 | + | |
22806 | + if (intdata & INT_ENP_PHY_INT) | |
22807 | + usbnet_defer_kevent(dev, EVENT_LINK_RESET); | |
22808 | + else | |
22809 | + netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n", | |
22810 | + intdata); | |
22811 | +} | |
22812 | + | |
22813 | +static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) | |
22814 | +{ | |
22815 | + return MAX_EEPROM_SIZE; | |
22816 | +} | |
22817 | + | |
22818 | +static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev, | |
22819 | + struct ethtool_eeprom *ee, u8 *data) | |
22820 | +{ | |
22821 | + struct usbnet *dev = netdev_priv(netdev); | |
22822 | + | |
22823 | + ee->magic = LAN75XX_EEPROM_MAGIC; | |
22824 | + | |
22825 | + return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data); | |
22826 | +} | |
22827 | + | |
22828 | +static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, | |
22829 | + struct ethtool_eeprom *ee, u8 *data) | |
22830 | +{ | |
22831 | + struct usbnet *dev = netdev_priv(netdev); | |
22832 | + | |
22833 | + if (ee->magic != LAN75XX_EEPROM_MAGIC) { | |
22834 | + netdev_warn(dev->net, "EEPROM: magic value mismatch: 0x%x\n", | |
22835 | + ee->magic); | |
22836 | + return -EINVAL; | |
22837 | + } | |
22838 | + | |
22839 | + return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); | |
22840 | +} | |
22841 | + | |
22842 | +static void smsc75xx_ethtool_get_wol(struct net_device *net, | |
22843 | + struct ethtool_wolinfo *wolinfo) | |
22844 | +{ | |
22845 | + struct usbnet *dev = netdev_priv(net); | |
22846 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
22847 | + | |
22848 | + wolinfo->supported = SUPPORTED_WAKE; | |
22849 | + wolinfo->wolopts = pdata->wolopts; | |
22850 | +} | |
22851 | + | |
22852 | +static int smsc75xx_ethtool_set_wol(struct net_device *net, | |
22853 | + struct ethtool_wolinfo *wolinfo) | |
22854 | +{ | |
22855 | + struct usbnet *dev = netdev_priv(net); | |
22856 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
22857 | + int ret; | |
22858 | + | |
22859 | + pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE; | |
22860 | + | |
22861 | + ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts); | |
22862 | + if (ret < 0) | |
22863 | + netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret); | |
22864 | + | |
22865 | + return ret; | |
22866 | +} | |
22867 | + | |
22868 | +static const struct ethtool_ops smsc75xx_ethtool_ops = { | |
22869 | + .get_link = usbnet_get_link, | |
22870 | + .nway_reset = usbnet_nway_reset, | |
22871 | + .get_drvinfo = usbnet_get_drvinfo, | |
22872 | + .get_msglevel = usbnet_get_msglevel, | |
22873 | + .set_msglevel = usbnet_set_msglevel, | |
22874 | + .get_settings = usbnet_get_settings, | |
22875 | + .set_settings = usbnet_set_settings, | |
22876 | + .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, | |
22877 | + .get_eeprom = smsc75xx_ethtool_get_eeprom, | |
22878 | + .set_eeprom = smsc75xx_ethtool_set_eeprom, | |
22879 | + .get_wol = smsc75xx_ethtool_get_wol, | |
22880 | + .set_wol = smsc75xx_ethtool_set_wol, | |
22881 | +}; | |
22882 | + | |
22883 | +static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
22884 | +{ | |
22885 | + struct usbnet *dev = netdev_priv(netdev); | |
22886 | + | |
22887 | + if (!netif_running(netdev)) | |
22888 | + return -EINVAL; | |
22889 | + | |
22890 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
22891 | +} | |
22892 | + | |
22893 | +static void smsc75xx_init_mac_address(struct usbnet *dev) | |
22894 | +{ | |
22895 | + /* try reading mac address from EEPROM */ | |
22896 | + if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, | |
22897 | + dev->net->dev_addr) == 0) { | |
22898 | + if (is_valid_ether_addr(dev->net->dev_addr)) { | |
22899 | + /* eeprom values are valid so use them */ | |
22900 | + netif_dbg(dev, ifup, dev->net, | |
22901 | + "MAC address read from EEPROM\n"); | |
22902 | + return; | |
22903 | + } | |
22904 | + } | |
22905 | + | |
22906 | + /* no eeprom, or eeprom values are invalid. generate random MAC */ | |
22907 | + eth_hw_addr_random(dev->net); | |
22908 | + netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); | |
22909 | +} | |
22910 | + | |
22911 | +static int smsc75xx_set_mac_address(struct usbnet *dev) | |
22912 | +{ | |
22913 | + u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | | |
22914 | + dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; | |
22915 | + u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; | |
22916 | + | |
22917 | + int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi); | |
22918 | + if (ret < 0) { | |
22919 | + netdev_warn(dev->net, "Failed to write RX_ADDRH: %d\n", ret); | |
22920 | + return ret; | |
22921 | + } | |
22922 | + | |
22923 | + ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo); | |
22924 | + if (ret < 0) { | |
22925 | + netdev_warn(dev->net, "Failed to write RX_ADDRL: %d\n", ret); | |
22926 | + return ret; | |
22927 | + } | |
22928 | + | |
22929 | + addr_hi |= ADDR_FILTX_FB_VALID; | |
22930 | + ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi); | |
22931 | + if (ret < 0) { | |
22932 | + netdev_warn(dev->net, "Failed to write ADDR_FILTX: %d\n", ret); | |
22933 | + return ret; | |
22934 | + } | |
22935 | + | |
22936 | + ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo); | |
22937 | + if (ret < 0) | |
22938 | + netdev_warn(dev->net, "Failed to write ADDR_FILTX+4: %d\n", ret); | |
22939 | + | |
22940 | + return ret; | |
22941 | +} | |
22942 | + | |
22943 | +static int smsc75xx_phy_initialize(struct usbnet *dev) | |
22944 | +{ | |
22945 | + int bmcr, ret, timeout = 0; | |
22946 | + | |
22947 | + /* Initialize MII structure */ | |
22948 | + dev->mii.dev = dev->net; | |
22949 | + dev->mii.mdio_read = smsc75xx_mdio_read; | |
22950 | + dev->mii.mdio_write = smsc75xx_mdio_write; | |
22951 | + dev->mii.phy_id_mask = 0x1f; | |
22952 | + dev->mii.reg_num_mask = 0x1f; | |
22953 | + dev->mii.supports_gmii = 1; | |
22954 | + dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; | |
22955 | + | |
22956 | + /* reset phy and wait for reset to complete */ | |
22957 | + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
22958 | + | |
22959 | + do { | |
22960 | + msleep(10); | |
22961 | + bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); | |
22962 | + if (bmcr < 0) { | |
22963 | + netdev_warn(dev->net, "Error reading MII_BMCR\n"); | |
22964 | + return bmcr; | |
22965 | + } | |
22966 | + timeout++; | |
22967 | + } while ((bmcr & BMCR_RESET) && (timeout < 100)); | |
22968 | + | |
22969 | + if (timeout >= 100) { | |
22970 | + netdev_warn(dev->net, "timeout on PHY Reset\n"); | |
22971 | + return -EIO; | |
22972 | + } | |
22973 | + | |
22974 | + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
22975 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | | |
22976 | + ADVERTISE_PAUSE_ASYM); | |
22977 | + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, | |
22978 | + ADVERTISE_1000FULL); | |
22979 | + | |
22980 | + /* read and write to clear phy interrupt status */ | |
22981 | + ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); | |
22982 | + if (ret < 0) { | |
22983 | + netdev_warn(dev->net, "Error reading PHY_INT_SRC\n"); | |
22984 | + return ret; | |
22985 | + } | |
22986 | + | |
22987 | + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff); | |
22988 | + | |
22989 | + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, | |
22990 | + PHY_INT_MASK_DEFAULT); | |
22991 | + mii_nway_restart(&dev->mii); | |
22992 | + | |
22993 | + netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n"); | |
22994 | + return 0; | |
22995 | +} | |
22996 | + | |
22997 | +static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size) | |
22998 | +{ | |
22999 | + int ret = 0; | |
23000 | + u32 buf; | |
23001 | + bool rxenabled; | |
23002 | + | |
23003 | + ret = smsc75xx_read_reg(dev, MAC_RX, &buf); | |
23004 | + if (ret < 0) { | |
23005 | + netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret); | |
23006 | + return ret; | |
23007 | + } | |
23008 | + | |
23009 | + rxenabled = ((buf & MAC_RX_RXEN) != 0); | |
23010 | + | |
23011 | + if (rxenabled) { | |
23012 | + buf &= ~MAC_RX_RXEN; | |
23013 | + ret = smsc75xx_write_reg(dev, MAC_RX, buf); | |
23014 | + if (ret < 0) { | |
23015 | + netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret); | |
23016 | + return ret; | |
23017 | + } | |
23018 | + } | |
23019 | + | |
23020 | + /* add 4 to size for FCS */ | |
23021 | + buf &= ~MAC_RX_MAX_SIZE; | |
23022 | + buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE); | |
23023 | + | |
23024 | + ret = smsc75xx_write_reg(dev, MAC_RX, buf); | |
23025 | + if (ret < 0) { | |
23026 | + netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret); | |
23027 | + return ret; | |
23028 | + } | |
23029 | + | |
23030 | + if (rxenabled) { | |
23031 | + buf |= MAC_RX_RXEN; | |
23032 | + ret = smsc75xx_write_reg(dev, MAC_RX, buf); | |
23033 | + if (ret < 0) { | |
23034 | + netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret); | |
23035 | + return ret; | |
23036 | + } | |
23037 | + } | |
23038 | + | |
23039 | + return 0; | |
23040 | +} | |
23041 | + | |
23042 | +static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) | |
23043 | +{ | |
23044 | + struct usbnet *dev = netdev_priv(netdev); | |
23045 | + int ret; | |
23046 | + | |
23047 | + if (new_mtu > MAX_SINGLE_PACKET_SIZE) | |
23048 | + return -EINVAL; | |
23049 | + | |
23050 | + ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN); | |
23051 | + if (ret < 0) { | |
23052 | + netdev_warn(dev->net, "Failed to set mac rx frame length\n"); | |
23053 | + return ret; | |
23054 | + } | |
23055 | + | |
23056 | + return usbnet_change_mtu(netdev, new_mtu); | |
23057 | +} | |
23058 | + | |
23059 | +/* Enable or disable Rx checksum offload engine */ | |
23060 | +static int smsc75xx_set_features(struct net_device *netdev, | |
23061 | + netdev_features_t features) | |
23062 | +{ | |
23063 | + struct usbnet *dev = netdev_priv(netdev); | |
23064 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23065 | + unsigned long flags; | |
23066 | + int ret; | |
23067 | + | |
23068 | + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | |
23069 | + | |
23070 | + if (features & NETIF_F_RXCSUM) | |
23071 | + pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; | |
23072 | + else | |
23073 | + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); | |
23074 | + | |
23075 | + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | |
23076 | + /* it's racing here! */ | |
23077 | + | |
23078 | + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | |
23079 | + if (ret < 0) | |
23080 | + netdev_warn(dev->net, "Error writing RFE_CTL\n"); | |
23081 | + | |
23082 | + return ret; | |
23083 | +} | |
23084 | + | |
23085 | +static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) | |
23086 | +{ | |
23087 | + int timeout = 0; | |
23088 | + | |
23089 | + do { | |
23090 | + u32 buf; | |
23091 | + int ret; | |
23092 | + | |
23093 | + ret = __smsc75xx_read_reg(dev, PMT_CTL, &buf, in_pm); | |
23094 | + | |
23095 | + if (ret < 0) { | |
23096 | + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); | |
23097 | + return ret; | |
23098 | + } | |
23099 | + | |
23100 | + if (buf & PMT_CTL_DEV_RDY) | |
23101 | + return 0; | |
23102 | + | |
23103 | + msleep(10); | |
23104 | + timeout++; | |
23105 | + } while (timeout < 100); | |
23106 | + | |
23107 | + netdev_warn(dev->net, "timeout waiting for device ready\n"); | |
23108 | + return -EIO; | |
23109 | +} | |
23110 | + | |
23111 | +static int smsc75xx_reset(struct usbnet *dev) | |
23112 | +{ | |
23113 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23114 | + u32 buf; | |
23115 | + int ret = 0, timeout; | |
23116 | + | |
23117 | + netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset\n"); | |
23118 | + | |
23119 | + ret = smsc75xx_wait_ready(dev, 0); | |
23120 | + if (ret < 0) { | |
23121 | + netdev_warn(dev->net, "device not ready in smsc75xx_reset\n"); | |
23122 | + return ret; | |
23123 | + } | |
23124 | + | |
23125 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23126 | + if (ret < 0) { | |
23127 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23128 | + return ret; | |
23129 | + } | |
23130 | + | |
23131 | + buf |= HW_CFG_LRST; | |
23132 | + | |
23133 | + ret = smsc75xx_write_reg(dev, HW_CFG, buf); | |
23134 | + if (ret < 0) { | |
23135 | + netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret); | |
23136 | + return ret; | |
23137 | + } | |
23138 | + | |
23139 | + timeout = 0; | |
23140 | + do { | |
23141 | + msleep(10); | |
23142 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23143 | + if (ret < 0) { | |
23144 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23145 | + return ret; | |
23146 | + } | |
23147 | + timeout++; | |
23148 | + } while ((buf & HW_CFG_LRST) && (timeout < 100)); | |
23149 | + | |
23150 | + if (timeout >= 100) { | |
23151 | + netdev_warn(dev->net, "timeout on completion of Lite Reset\n"); | |
23152 | + return -EIO; | |
23153 | + } | |
23154 | + | |
23155 | + netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY\n"); | |
23156 | + | |
23157 | + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); | |
23158 | + if (ret < 0) { | |
23159 | + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); | |
23160 | + return ret; | |
23161 | + } | |
23162 | + | |
23163 | + buf |= PMT_CTL_PHY_RST; | |
23164 | + | |
23165 | + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); | |
23166 | + if (ret < 0) { | |
23167 | + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret); | |
23168 | + return ret; | |
23169 | + } | |
23170 | + | |
23171 | + timeout = 0; | |
23172 | + do { | |
23173 | + msleep(10); | |
23174 | + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); | |
23175 | + if (ret < 0) { | |
23176 | + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); | |
23177 | + return ret; | |
23178 | + } | |
23179 | + timeout++; | |
23180 | + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); | |
23181 | + | |
23182 | + if (timeout >= 100) { | |
23183 | + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); | |
23184 | + return -EIO; | |
23185 | + } | |
23186 | + | |
23187 | + netif_dbg(dev, ifup, dev->net, "PHY reset complete\n"); | |
23188 | + | |
23189 | + ret = smsc75xx_set_mac_address(dev); | |
23190 | + if (ret < 0) { | |
23191 | + netdev_warn(dev->net, "Failed to set mac address\n"); | |
23192 | + return ret; | |
23193 | + } | |
23194 | + | |
23195 | + netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n", | |
23196 | + dev->net->dev_addr); | |
23197 | + | |
23198 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23199 | + if (ret < 0) { | |
23200 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23201 | + return ret; | |
23202 | + } | |
23203 | + | |
23204 | + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n", | |
23205 | + buf); | |
23206 | + | |
23207 | + buf |= HW_CFG_BIR; | |
23208 | + | |
23209 | + ret = smsc75xx_write_reg(dev, HW_CFG, buf); | |
23210 | + if (ret < 0) { | |
23211 | + netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret); | |
23212 | + return ret; | |
23213 | + } | |
23214 | + | |
23215 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23216 | + if (ret < 0) { | |
23217 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23218 | + return ret; | |
23219 | + } | |
23220 | + | |
23221 | + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after writing HW_CFG_BIR: 0x%08x\n", | |
23222 | + buf); | |
23223 | + | |
23224 | + if (!turbo_mode) { | |
23225 | + buf = 0; | |
23226 | + dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; | |
23227 | + } else if (dev->udev->speed == USB_SPEED_HIGH) { | |
23228 | + buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; | |
23229 | + dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; | |
23230 | + } else { | |
23231 | + buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; | |
23232 | + dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; | |
23233 | + } | |
23234 | + | |
23235 | + netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", | |
23236 | + (ulong)dev->rx_urb_size); | |
23237 | + | |
23238 | + ret = smsc75xx_write_reg(dev, BURST_CAP, buf); | |
23239 | + if (ret < 0) { | |
23240 | + netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret); | |
23241 | + return ret; | |
23242 | + } | |
23243 | + | |
23244 | + ret = smsc75xx_read_reg(dev, BURST_CAP, &buf); | |
23245 | + if (ret < 0) { | |
23246 | + netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret); | |
23247 | + return ret; | |
23248 | + } | |
23249 | + | |
23250 | + netif_dbg(dev, ifup, dev->net, | |
23251 | + "Read Value from BURST_CAP after writing: 0x%08x\n", buf); | |
23252 | + | |
23253 | + ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); | |
23254 | + if (ret < 0) { | |
23255 | + netdev_warn(dev->net, "Failed to write BULK_IN_DLY: %d\n", ret); | |
23256 | + return ret; | |
23257 | + } | |
23258 | + | |
23259 | + ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf); | |
23260 | + if (ret < 0) { | |
23261 | + netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret); | |
23262 | + return ret; | |
23263 | + } | |
23264 | + | |
23265 | + netif_dbg(dev, ifup, dev->net, | |
23266 | + "Read Value from BULK_IN_DLY after writing: 0x%08x\n", buf); | |
23267 | + | |
23268 | + if (turbo_mode) { | |
23269 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23270 | + if (ret < 0) { | |
23271 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23272 | + return ret; | |
23273 | + } | |
23274 | + | |
23275 | + netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf); | |
23276 | + | |
23277 | + buf |= (HW_CFG_MEF | HW_CFG_BCE); | |
23278 | + | |
23279 | + ret = smsc75xx_write_reg(dev, HW_CFG, buf); | |
23280 | + if (ret < 0) { | |
23281 | + netdev_warn(dev->net, "Failed to write HW_CFG: %d\n", ret); | |
23282 | + return ret; | |
23283 | + } | |
23284 | + | |
23285 | + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); | |
23286 | + if (ret < 0) { | |
23287 | + netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret); | |
23288 | + return ret; | |
23289 | + } | |
23290 | + | |
23291 | + netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x\n", buf); | |
23292 | + } | |
23293 | + | |
23294 | + /* set FIFO sizes */ | |
23295 | + buf = (MAX_RX_FIFO_SIZE - 512) / 512; | |
23296 | + ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf); | |
23297 | + if (ret < 0) { | |
23298 | + netdev_warn(dev->net, "Failed to write FCT_RX_FIFO_END: %d\n", ret); | |
23299 | + return ret; | |
23300 | + } | |
23301 | + | |
23302 | + netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x\n", buf); | |
23303 | + | |
23304 | + buf = (MAX_TX_FIFO_SIZE - 512) / 512; | |
23305 | + ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf); | |
23306 | + if (ret < 0) { | |
23307 | + netdev_warn(dev->net, "Failed to write FCT_TX_FIFO_END: %d\n", ret); | |
23308 | + return ret; | |
23309 | + } | |
23310 | + | |
23311 | + netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x\n", buf); | |
23312 | + | |
23313 | + ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); | |
23314 | + if (ret < 0) { | |
23315 | + netdev_warn(dev->net, "Failed to write INT_STS: %d\n", ret); | |
23316 | + return ret; | |
23317 | + } | |
23318 | + | |
23319 | + ret = smsc75xx_read_reg(dev, ID_REV, &buf); | |
23320 | + if (ret < 0) { | |
23321 | + netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret); | |
23322 | + return ret; | |
23323 | + } | |
23324 | + | |
23325 | + netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", buf); | |
23326 | + | |
23327 | + ret = smsc75xx_read_reg(dev, E2P_CMD, &buf); | |
23328 | + if (ret < 0) { | |
23329 | + netdev_warn(dev->net, "Failed to read E2P_CMD: %d\n", ret); | |
23330 | + return ret; | |
23331 | + } | |
23332 | + | |
23333 | + /* only set default GPIO/LED settings if no EEPROM is detected */ | |
23334 | + if (!(buf & E2P_CMD_LOADED)) { | |
23335 | + ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); | |
23336 | + if (ret < 0) { | |
23337 | + netdev_warn(dev->net, "Failed to read LED_GPIO_CFG: %d\n", ret); | |
23338 | + return ret; | |
23339 | + } | |
23340 | + | |
23341 | + buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); | |
23342 | + buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; | |
23343 | + | |
23344 | + ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); | |
23345 | + if (ret < 0) { | |
23346 | + netdev_warn(dev->net, "Failed to write LED_GPIO_CFG: %d\n", ret); | |
23347 | + return ret; | |
23348 | + } | |
23349 | + } | |
23350 | + | |
23351 | + ret = smsc75xx_write_reg(dev, FLOW, 0); | |
23352 | + if (ret < 0) { | |
23353 | + netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret); | |
23354 | + return ret; | |
23355 | + } | |
23356 | + | |
23357 | + ret = smsc75xx_write_reg(dev, FCT_FLOW, 0); | |
23358 | + if (ret < 0) { | |
23359 | + netdev_warn(dev->net, "Failed to write FCT_FLOW: %d\n", ret); | |
23360 | + return ret; | |
23361 | + } | |
23362 | + | |
23363 | + /* Don't need rfe_ctl_lock during initialisation */ | |
23364 | + ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); | |
23365 | + if (ret < 0) { | |
23366 | + netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret); | |
23367 | + return ret; | |
23368 | + } | |
23369 | + | |
23370 | + pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF; | |
23371 | + | |
23372 | + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | |
23373 | + if (ret < 0) { | |
23374 | + netdev_warn(dev->net, "Failed to write RFE_CTL: %d\n", ret); | |
23375 | + return ret; | |
23376 | + } | |
23377 | + | |
23378 | + ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); | |
23379 | + if (ret < 0) { | |
23380 | + netdev_warn(dev->net, "Failed to read RFE_CTL: %d\n", ret); | |
23381 | + return ret; | |
23382 | + } | |
23383 | + | |
23384 | + netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x\n", | |
23385 | + pdata->rfe_ctl); | |
23386 | + | |
23387 | + /* Enable or disable checksum offload engines */ | |
23388 | + smsc75xx_set_features(dev->net, dev->net->features); | |
23389 | + | |
23390 | + smsc75xx_set_multicast(dev->net); | |
23391 | + | |
23392 | + ret = smsc75xx_phy_initialize(dev); | |
23393 | + if (ret < 0) { | |
23394 | + netdev_warn(dev->net, "Failed to initialize PHY: %d\n", ret); | |
23395 | + return ret; | |
23396 | + } | |
23397 | + | |
23398 | + ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf); | |
23399 | + if (ret < 0) { | |
23400 | + netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret); | |
23401 | + return ret; | |
23402 | + } | |
23403 | + | |
23404 | + /* enable PHY interrupts */ | |
23405 | + buf |= INT_ENP_PHY_INT; | |
23406 | + | |
23407 | + ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); | |
23408 | + if (ret < 0) { | |
23409 | + netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret); | |
23410 | + return ret; | |
23411 | + } | |
23412 | + | |
23413 | + /* allow mac to detect speed and duplex from phy */ | |
23414 | + ret = smsc75xx_read_reg(dev, MAC_CR, &buf); | |
23415 | + if (ret < 0) { | |
23416 | + netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret); | |
23417 | + return ret; | |
23418 | + } | |
23419 | + | |
23420 | + buf |= (MAC_CR_ADD | MAC_CR_ASD); | |
23421 | + ret = smsc75xx_write_reg(dev, MAC_CR, buf); | |
23422 | + if (ret < 0) { | |
23423 | + netdev_warn(dev->net, "Failed to write MAC_CR: %d\n", ret); | |
23424 | + return ret; | |
23425 | + } | |
23426 | + | |
23427 | + ret = smsc75xx_read_reg(dev, MAC_TX, &buf); | |
23428 | + if (ret < 0) { | |
23429 | + netdev_warn(dev->net, "Failed to read MAC_TX: %d\n", ret); | |
23430 | + return ret; | |
23431 | + } | |
23432 | + | |
23433 | + buf |= MAC_TX_TXEN; | |
23434 | + | |
23435 | + ret = smsc75xx_write_reg(dev, MAC_TX, buf); | |
23436 | + if (ret < 0) { | |
23437 | + netdev_warn(dev->net, "Failed to write MAC_TX: %d\n", ret); | |
23438 | + return ret; | |
23439 | + } | |
23440 | + | |
23441 | + netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x\n", buf); | |
23442 | + | |
23443 | + ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf); | |
23444 | + if (ret < 0) { | |
23445 | + netdev_warn(dev->net, "Failed to read FCT_TX_CTL: %d\n", ret); | |
23446 | + return ret; | |
23447 | + } | |
23448 | + | |
23449 | + buf |= FCT_TX_CTL_EN; | |
23450 | + | |
23451 | + ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf); | |
23452 | + if (ret < 0) { | |
23453 | + netdev_warn(dev->net, "Failed to write FCT_TX_CTL: %d\n", ret); | |
23454 | + return ret; | |
23455 | + } | |
23456 | + | |
23457 | + netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf); | |
23458 | + | |
23459 | + ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN); | |
23460 | + if (ret < 0) { | |
23461 | + netdev_warn(dev->net, "Failed to set max rx frame length\n"); | |
23462 | + return ret; | |
23463 | + } | |
23464 | + | |
23465 | + ret = smsc75xx_read_reg(dev, MAC_RX, &buf); | |
23466 | + if (ret < 0) { | |
23467 | + netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret); | |
23468 | + return ret; | |
23469 | + } | |
23470 | + | |
23471 | + buf |= MAC_RX_RXEN; | |
23472 | + | |
23473 | + ret = smsc75xx_write_reg(dev, MAC_RX, buf); | |
23474 | + if (ret < 0) { | |
23475 | + netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret); | |
23476 | + return ret; | |
23477 | + } | |
23478 | + | |
23479 | + netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x\n", buf); | |
23480 | + | |
23481 | + ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf); | |
23482 | + if (ret < 0) { | |
23483 | + netdev_warn(dev->net, "Failed to read FCT_RX_CTL: %d\n", ret); | |
23484 | + return ret; | |
23485 | + } | |
23486 | + | |
23487 | + buf |= FCT_RX_CTL_EN; | |
23488 | + | |
23489 | + ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf); | |
23490 | + if (ret < 0) { | |
23491 | + netdev_warn(dev->net, "Failed to write FCT_RX_CTL: %d\n", ret); | |
23492 | + return ret; | |
23493 | + } | |
23494 | + | |
23495 | + netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x\n", buf); | |
23496 | + | |
23497 | + netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0\n"); | |
23498 | + return 0; | |
23499 | +} | |
23500 | + | |
23501 | +static const struct net_device_ops smsc75xx_netdev_ops = { | |
23502 | + .ndo_open = usbnet_open, | |
23503 | + .ndo_stop = usbnet_stop, | |
23504 | + .ndo_start_xmit = usbnet_start_xmit, | |
23505 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
23506 | + .ndo_change_mtu = smsc75xx_change_mtu, | |
23507 | + .ndo_set_mac_address = eth_mac_addr, | |
23508 | + .ndo_validate_addr = eth_validate_addr, | |
23509 | + .ndo_do_ioctl = smsc75xx_ioctl, | |
23510 | + .ndo_set_rx_mode = smsc75xx_set_multicast, | |
23511 | + .ndo_set_features = smsc75xx_set_features, | |
23512 | +}; | |
23513 | + | |
23514 | +static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) | |
23515 | +{ | |
23516 | + struct smsc75xx_priv *pdata = NULL; | |
23517 | + int ret; | |
23518 | + | |
23519 | + printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); | |
23520 | + | |
23521 | + ret = usbnet_get_endpoints(dev, intf); | |
23522 | + if (ret < 0) { | |
23523 | + netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret); | |
23524 | + return ret; | |
23525 | + } | |
23526 | + | |
23527 | + dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv), | |
23528 | + GFP_KERNEL); | |
23529 | + | |
23530 | + pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23531 | + if (!pdata) | |
23532 | + return -ENOMEM; | |
23533 | + | |
23534 | + pdata->dev = dev; | |
23535 | + | |
23536 | + spin_lock_init(&pdata->rfe_ctl_lock); | |
23537 | + mutex_init(&pdata->dataport_mutex); | |
23538 | + | |
23539 | + INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); | |
23540 | + | |
23541 | + if (DEFAULT_TX_CSUM_ENABLE) | |
23542 | + dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; | |
23543 | + | |
23544 | + if (DEFAULT_RX_CSUM_ENABLE) | |
23545 | + dev->net->features |= NETIF_F_RXCSUM; | |
23546 | + | |
23547 | + dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | | |
23548 | + NETIF_F_RXCSUM; | |
23549 | + | |
23550 | + ret = smsc75xx_wait_ready(dev, 0); | |
23551 | + if (ret < 0) { | |
23552 | + netdev_warn(dev->net, "device not ready in smsc75xx_bind\n"); | |
23553 | + return ret; | |
23554 | + } | |
23555 | + | |
23556 | + smsc75xx_init_mac_address(dev); | |
23557 | + | |
23558 | + /* Init all registers */ | |
23559 | + ret = smsc75xx_reset(dev); | |
23560 | + if (ret < 0) { | |
23561 | + netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret); | |
23562 | + return ret; | |
23563 | + } | |
23564 | + | |
23565 | + dev->net->netdev_ops = &smsc75xx_netdev_ops; | |
23566 | + dev->net->ethtool_ops = &smsc75xx_ethtool_ops; | |
23567 | + dev->net->flags |= IFF_MULTICAST; | |
23568 | + dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; | |
23569 | + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | |
23570 | + return 0; | |
23571 | +} | |
23572 | + | |
23573 | +static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) | |
23574 | +{ | |
23575 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23576 | + if (pdata) { | |
23577 | + netif_dbg(dev, ifdown, dev->net, "free pdata\n"); | |
23578 | + kfree(pdata); | |
23579 | + pdata = NULL; | |
23580 | + dev->data[0] = 0; | |
23581 | + } | |
23582 | +} | |
23583 | + | |
23584 | +static u16 smsc_crc(const u8 *buffer, size_t len) | |
23585 | +{ | |
23586 | + return bitrev16(crc16(0xFFFF, buffer, len)); | |
23587 | +} | |
23588 | + | |
23589 | +static int smsc75xx_write_wuff(struct usbnet *dev, int filter, u32 wuf_cfg, | |
23590 | + u32 wuf_mask1) | |
23591 | +{ | |
23592 | + int cfg_base = WUF_CFGX + filter * 4; | |
23593 | + int mask_base = WUF_MASKX + filter * 16; | |
23594 | + int ret; | |
23595 | + | |
23596 | + ret = smsc75xx_write_reg(dev, cfg_base, wuf_cfg); | |
23597 | + if (ret < 0) { | |
23598 | + netdev_warn(dev->net, "Error writing WUF_CFGX\n"); | |
23599 | + return ret; | |
23600 | + } | |
23601 | + | |
23602 | + ret = smsc75xx_write_reg(dev, mask_base, wuf_mask1); | |
23603 | + if (ret < 0) { | |
23604 | + netdev_warn(dev->net, "Error writing WUF_MASKX\n"); | |
23605 | + return ret; | |
23606 | + } | |
23607 | + | |
23608 | + ret = smsc75xx_write_reg(dev, mask_base + 4, 0); | |
23609 | + if (ret < 0) { | |
23610 | + netdev_warn(dev->net, "Error writing WUF_MASKX\n"); | |
23611 | + return ret; | |
23612 | + } | |
23613 | + | |
23614 | + ret = smsc75xx_write_reg(dev, mask_base + 8, 0); | |
23615 | + if (ret < 0) { | |
23616 | + netdev_warn(dev->net, "Error writing WUF_MASKX\n"); | |
23617 | + return ret; | |
23618 | + } | |
23619 | + | |
23620 | + ret = smsc75xx_write_reg(dev, mask_base + 12, 0); | |
23621 | + if (ret < 0) { | |
23622 | + netdev_warn(dev->net, "Error writing WUF_MASKX\n"); | |
23623 | + return ret; | |
23624 | + } | |
23625 | + | |
23626 | + return 0; | |
23627 | +} | |
23628 | + | |
23629 | +static int smsc75xx_enter_suspend0(struct usbnet *dev) | |
23630 | +{ | |
23631 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23632 | + u32 val; | |
23633 | + int ret; | |
23634 | + | |
23635 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
23636 | + if (ret < 0) { | |
23637 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
23638 | + return ret; | |
23639 | + } | |
23640 | + | |
23641 | + val &= (~(PMT_CTL_SUS_MODE | PMT_CTL_PHY_RST)); | |
23642 | + val |= PMT_CTL_SUS_MODE_0 | PMT_CTL_WOL_EN | PMT_CTL_WUPS; | |
23643 | + | |
23644 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23645 | + if (ret < 0) { | |
23646 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23647 | + return ret; | |
23648 | + } | |
23649 | + | |
23650 | + pdata->suspend_flags |= SUSPEND_SUSPEND0; | |
23651 | + | |
23652 | + return 0; | |
23653 | +} | |
23654 | + | |
23655 | +static int smsc75xx_enter_suspend1(struct usbnet *dev) | |
23656 | +{ | |
23657 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23658 | + u32 val; | |
23659 | + int ret; | |
23660 | + | |
23661 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
23662 | + if (ret < 0) { | |
23663 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
23664 | + return ret; | |
23665 | + } | |
23666 | + | |
23667 | + val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST); | |
23668 | + val |= PMT_CTL_SUS_MODE_1; | |
23669 | + | |
23670 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23671 | + if (ret < 0) { | |
23672 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23673 | + return ret; | |
23674 | + } | |
23675 | + | |
23676 | + /* clear wol status, enable energy detection */ | |
23677 | + val &= ~PMT_CTL_WUPS; | |
23678 | + val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN); | |
23679 | + | |
23680 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23681 | + if (ret < 0) { | |
23682 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23683 | + return ret; | |
23684 | + } | |
23685 | + | |
23686 | + pdata->suspend_flags |= SUSPEND_SUSPEND1; | |
23687 | + | |
23688 | + return 0; | |
23689 | +} | |
23690 | + | |
23691 | +static int smsc75xx_enter_suspend2(struct usbnet *dev) | |
23692 | +{ | |
23693 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23694 | + u32 val; | |
23695 | + int ret; | |
23696 | + | |
23697 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
23698 | + if (ret < 0) { | |
23699 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
23700 | + return ret; | |
23701 | + } | |
23702 | + | |
23703 | + val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST); | |
23704 | + val |= PMT_CTL_SUS_MODE_2; | |
23705 | + | |
23706 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23707 | + if (ret < 0) { | |
23708 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23709 | + return ret; | |
23710 | + } | |
23711 | + | |
23712 | + pdata->suspend_flags |= SUSPEND_SUSPEND2; | |
23713 | + | |
23714 | + return 0; | |
23715 | +} | |
23716 | + | |
23717 | +static int smsc75xx_enter_suspend3(struct usbnet *dev) | |
23718 | +{ | |
23719 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23720 | + u32 val; | |
23721 | + int ret; | |
23722 | + | |
23723 | + ret = smsc75xx_read_reg_nopm(dev, FCT_RX_CTL, &val); | |
23724 | + if (ret < 0) { | |
23725 | + netdev_warn(dev->net, "Error reading FCT_RX_CTL\n"); | |
23726 | + return ret; | |
23727 | + } | |
23728 | + | |
23729 | + if (val & FCT_RX_CTL_RXUSED) { | |
23730 | + netdev_dbg(dev->net, "rx fifo not empty in autosuspend\n"); | |
23731 | + return -EBUSY; | |
23732 | + } | |
23733 | + | |
23734 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
23735 | + if (ret < 0) { | |
23736 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
23737 | + return ret; | |
23738 | + } | |
23739 | + | |
23740 | + val &= ~(PMT_CTL_SUS_MODE | PMT_CTL_WUPS | PMT_CTL_PHY_RST); | |
23741 | + val |= PMT_CTL_SUS_MODE_3 | PMT_CTL_RES_CLR_WKP_EN; | |
23742 | + | |
23743 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23744 | + if (ret < 0) { | |
23745 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23746 | + return ret; | |
23747 | + } | |
23748 | + | |
23749 | + /* clear wol status */ | |
23750 | + val &= ~PMT_CTL_WUPS; | |
23751 | + val |= PMT_CTL_WUPS_WOL; | |
23752 | + | |
23753 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23754 | + if (ret < 0) { | |
23755 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23756 | + return ret; | |
23757 | + } | |
23758 | + | |
23759 | + pdata->suspend_flags |= SUSPEND_SUSPEND3; | |
23760 | + | |
23761 | + return 0; | |
23762 | +} | |
23763 | + | |
23764 | +static int smsc75xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask) | |
23765 | +{ | |
23766 | + struct mii_if_info *mii = &dev->mii; | |
23767 | + int ret; | |
23768 | + | |
23769 | + netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n"); | |
23770 | + | |
23771 | + /* read to clear */ | |
23772 | + ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC); | |
23773 | + if (ret < 0) { | |
23774 | + netdev_warn(dev->net, "Error reading PHY_INT_SRC\n"); | |
23775 | + return ret; | |
23776 | + } | |
23777 | + | |
23778 | + /* enable interrupt source */ | |
23779 | + ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK); | |
23780 | + if (ret < 0) { | |
23781 | + netdev_warn(dev->net, "Error reading PHY_INT_MASK\n"); | |
23782 | + return ret; | |
23783 | + } | |
23784 | + | |
23785 | + ret |= mask; | |
23786 | + | |
23787 | + smsc75xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret); | |
23788 | + | |
23789 | + return 0; | |
23790 | +} | |
23791 | + | |
23792 | +static int smsc75xx_link_ok_nopm(struct usbnet *dev) | |
23793 | +{ | |
23794 | + struct mii_if_info *mii = &dev->mii; | |
23795 | + int ret; | |
23796 | + | |
23797 | + /* first, a dummy read, needed to latch some MII phys */ | |
23798 | + ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR); | |
23799 | + if (ret < 0) { | |
23800 | + netdev_warn(dev->net, "Error reading MII_BMSR\n"); | |
23801 | + return ret; | |
23802 | + } | |
23803 | + | |
23804 | + ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR); | |
23805 | + if (ret < 0) { | |
23806 | + netdev_warn(dev->net, "Error reading MII_BMSR\n"); | |
23807 | + return ret; | |
23808 | + } | |
23809 | + | |
23810 | + return !!(ret & BMSR_LSTATUS); | |
23811 | +} | |
23812 | + | |
23813 | +static int smsc75xx_autosuspend(struct usbnet *dev, u32 link_up) | |
23814 | +{ | |
23815 | + int ret; | |
23816 | + | |
23817 | + if (!netif_running(dev->net)) { | |
23818 | + /* interface is ifconfig down so fully power down hw */ | |
23819 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n"); | |
23820 | + return smsc75xx_enter_suspend2(dev); | |
23821 | + } | |
23822 | + | |
23823 | + if (!link_up) { | |
23824 | + /* link is down so enter EDPD mode */ | |
23825 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n"); | |
23826 | + | |
23827 | + /* enable PHY wakeup events for if cable is attached */ | |
23828 | + ret = smsc75xx_enable_phy_wakeup_interrupts(dev, | |
23829 | + PHY_INT_MASK_ANEG_COMP); | |
23830 | + if (ret < 0) { | |
23831 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
23832 | + return ret; | |
23833 | + } | |
23834 | + | |
23835 | + netdev_info(dev->net, "entering SUSPEND1 mode\n"); | |
23836 | + return smsc75xx_enter_suspend1(dev); | |
23837 | + } | |
23838 | + | |
23839 | + /* enable PHY wakeup events so we remote wakeup if cable is pulled */ | |
23840 | + ret = smsc75xx_enable_phy_wakeup_interrupts(dev, | |
23841 | + PHY_INT_MASK_LINK_DOWN); | |
23842 | + if (ret < 0) { | |
23843 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
23844 | + return ret; | |
23845 | + } | |
23846 | + | |
23847 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n"); | |
23848 | + return smsc75xx_enter_suspend3(dev); | |
23849 | +} | |
23850 | + | |
23851 | +static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message) | |
23852 | +{ | |
23853 | + struct usbnet *dev = usb_get_intfdata(intf); | |
23854 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
23855 | + u32 val, link_up; | |
23856 | + int ret; | |
23857 | + | |
23858 | + ret = usbnet_suspend(intf, message); | |
23859 | + if (ret < 0) { | |
23860 | + netdev_warn(dev->net, "usbnet_suspend error\n"); | |
23861 | + return ret; | |
23862 | + } | |
23863 | + | |
23864 | + if (pdata->suspend_flags) { | |
23865 | + netdev_warn(dev->net, "error during last resume\n"); | |
23866 | + pdata->suspend_flags = 0; | |
23867 | + } | |
23868 | + | |
23869 | + /* determine if link is up using only _nopm functions */ | |
23870 | + link_up = smsc75xx_link_ok_nopm(dev); | |
23871 | + | |
23872 | + if (message.event == PM_EVENT_AUTO_SUSPEND) { | |
23873 | + ret = smsc75xx_autosuspend(dev, link_up); | |
23874 | + goto done; | |
23875 | + } | |
23876 | + | |
23877 | + /* if we get this far we're not autosuspending */ | |
23878 | + /* if no wol options set, or if link is down and we're not waking on | |
23879 | + * PHY activity, enter lowest power SUSPEND2 mode | |
23880 | + */ | |
23881 | + if (!(pdata->wolopts & SUPPORTED_WAKE) || | |
23882 | + !(link_up || (pdata->wolopts & WAKE_PHY))) { | |
23883 | + netdev_info(dev->net, "entering SUSPEND2 mode\n"); | |
23884 | + | |
23885 | + /* disable energy detect (link up) & wake up events */ | |
23886 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
23887 | + if (ret < 0) { | |
23888 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
23889 | + goto done; | |
23890 | + } | |
23891 | + | |
23892 | + val &= ~(WUCSR_MPEN | WUCSR_WUEN); | |
23893 | + | |
23894 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
23895 | + if (ret < 0) { | |
23896 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
23897 | + goto done; | |
23898 | + } | |
23899 | + | |
23900 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
23901 | + if (ret < 0) { | |
23902 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
23903 | + goto done; | |
23904 | + } | |
23905 | + | |
23906 | + val &= ~(PMT_CTL_ED_EN | PMT_CTL_WOL_EN); | |
23907 | + | |
23908 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
23909 | + if (ret < 0) { | |
23910 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
23911 | + goto done; | |
23912 | + } | |
23913 | + | |
23914 | + ret = smsc75xx_enter_suspend2(dev); | |
23915 | + goto done; | |
23916 | + } | |
23917 | + | |
23918 | + if (pdata->wolopts & WAKE_PHY) { | |
23919 | + ret = smsc75xx_enable_phy_wakeup_interrupts(dev, | |
23920 | + (PHY_INT_MASK_ANEG_COMP | PHY_INT_MASK_LINK_DOWN)); | |
23921 | + if (ret < 0) { | |
23922 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
23923 | + goto done; | |
23924 | + } | |
23925 | + | |
23926 | + /* if link is down then configure EDPD and enter SUSPEND1, | |
23927 | + * otherwise enter SUSPEND0 below | |
23928 | + */ | |
23929 | + if (!link_up) { | |
23930 | + struct mii_if_info *mii = &dev->mii; | |
23931 | + netdev_info(dev->net, "entering SUSPEND1 mode\n"); | |
23932 | + | |
23933 | + /* enable energy detect power-down mode */ | |
23934 | + ret = smsc75xx_mdio_read_nopm(dev->net, mii->phy_id, | |
23935 | + PHY_MODE_CTRL_STS); | |
23936 | + if (ret < 0) { | |
23937 | + netdev_warn(dev->net, "Error reading PHY_MODE_CTRL_STS\n"); | |
23938 | + goto done; | |
23939 | + } | |
23940 | + | |
23941 | + ret |= MODE_CTRL_STS_EDPWRDOWN; | |
23942 | + | |
23943 | + smsc75xx_mdio_write_nopm(dev->net, mii->phy_id, | |
23944 | + PHY_MODE_CTRL_STS, ret); | |
23945 | + | |
23946 | + /* enter SUSPEND1 mode */ | |
23947 | + ret = smsc75xx_enter_suspend1(dev); | |
23948 | + goto done; | |
23949 | + } | |
23950 | + } | |
23951 | + | |
23952 | + if (pdata->wolopts & (WAKE_MCAST | WAKE_ARP)) { | |
23953 | + int i, filter = 0; | |
23954 | + | |
23955 | + /* disable all filters */ | |
23956 | + for (i = 0; i < WUF_NUM; i++) { | |
23957 | + ret = smsc75xx_write_reg_nopm(dev, WUF_CFGX + i * 4, 0); | |
23958 | + if (ret < 0) { | |
23959 | + netdev_warn(dev->net, "Error writing WUF_CFGX\n"); | |
23960 | + goto done; | |
23961 | + } | |
23962 | + } | |
23963 | + | |
23964 | + if (pdata->wolopts & WAKE_MCAST) { | |
23965 | + const u8 mcast[] = {0x01, 0x00, 0x5E}; | |
23966 | + netdev_info(dev->net, "enabling multicast detection\n"); | |
23967 | + | |
23968 | + val = WUF_CFGX_EN | WUF_CFGX_ATYPE_MULTICAST | |
23969 | + | smsc_crc(mcast, 3); | |
23970 | + ret = smsc75xx_write_wuff(dev, filter++, val, 0x0007); | |
23971 | + if (ret < 0) { | |
23972 | + netdev_warn(dev->net, "Error writing wakeup filter\n"); | |
23973 | + goto done; | |
23974 | + } | |
23975 | + } | |
23976 | + | |
23977 | + if (pdata->wolopts & WAKE_ARP) { | |
23978 | + const u8 arp[] = {0x08, 0x06}; | |
23979 | + netdev_info(dev->net, "enabling ARP detection\n"); | |
23980 | + | |
23981 | + val = WUF_CFGX_EN | WUF_CFGX_ATYPE_ALL | (0x0C << 16) | |
23982 | + | smsc_crc(arp, 2); | |
23983 | + ret = smsc75xx_write_wuff(dev, filter++, val, 0x0003); | |
23984 | + if (ret < 0) { | |
23985 | + netdev_warn(dev->net, "Error writing wakeup filter\n"); | |
23986 | + goto done; | |
23987 | + } | |
23988 | + } | |
23989 | + | |
23990 | + /* clear any pending pattern match packet status */ | |
23991 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
23992 | + if (ret < 0) { | |
23993 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
23994 | + goto done; | |
23995 | + } | |
23996 | + | |
23997 | + val |= WUCSR_WUFR; | |
23998 | + | |
23999 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24000 | + if (ret < 0) { | |
24001 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24002 | + goto done; | |
24003 | + } | |
24004 | + | |
24005 | + netdev_info(dev->net, "enabling packet match detection\n"); | |
24006 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24007 | + if (ret < 0) { | |
24008 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24009 | + goto done; | |
24010 | + } | |
24011 | + | |
24012 | + val |= WUCSR_WUEN; | |
24013 | + | |
24014 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24015 | + if (ret < 0) { | |
24016 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24017 | + goto done; | |
24018 | + } | |
24019 | + } else { | |
24020 | + netdev_info(dev->net, "disabling packet match detection\n"); | |
24021 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24022 | + if (ret < 0) { | |
24023 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24024 | + goto done; | |
24025 | + } | |
24026 | + | |
24027 | + val &= ~WUCSR_WUEN; | |
24028 | + | |
24029 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24030 | + if (ret < 0) { | |
24031 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24032 | + goto done; | |
24033 | + } | |
24034 | + } | |
24035 | + | |
24036 | + /* disable magic, bcast & unicast wakeup sources */ | |
24037 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24038 | + if (ret < 0) { | |
24039 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24040 | + goto done; | |
24041 | + } | |
24042 | + | |
24043 | + val &= ~(WUCSR_MPEN | WUCSR_BCST_EN | WUCSR_PFDA_EN); | |
24044 | + | |
24045 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24046 | + if (ret < 0) { | |
24047 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24048 | + goto done; | |
24049 | + } | |
24050 | + | |
24051 | + if (pdata->wolopts & WAKE_PHY) { | |
24052 | + netdev_info(dev->net, "enabling PHY wakeup\n"); | |
24053 | + | |
24054 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
24055 | + if (ret < 0) { | |
24056 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
24057 | + goto done; | |
24058 | + } | |
24059 | + | |
24060 | + /* clear wol status, enable energy detection */ | |
24061 | + val &= ~PMT_CTL_WUPS; | |
24062 | + val |= (PMT_CTL_WUPS_ED | PMT_CTL_ED_EN); | |
24063 | + | |
24064 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
24065 | + if (ret < 0) { | |
24066 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
24067 | + goto done; | |
24068 | + } | |
24069 | + } | |
24070 | + | |
24071 | + if (pdata->wolopts & WAKE_MAGIC) { | |
24072 | + netdev_info(dev->net, "enabling magic packet wakeup\n"); | |
24073 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24074 | + if (ret < 0) { | |
24075 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24076 | + goto done; | |
24077 | + } | |
24078 | + | |
24079 | + /* clear any pending magic packet status */ | |
24080 | + val |= WUCSR_MPR | WUCSR_MPEN; | |
24081 | + | |
24082 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24083 | + if (ret < 0) { | |
24084 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24085 | + goto done; | |
24086 | + } | |
24087 | + } | |
24088 | + | |
24089 | + if (pdata->wolopts & WAKE_BCAST) { | |
24090 | + netdev_info(dev->net, "enabling broadcast detection\n"); | |
24091 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24092 | + if (ret < 0) { | |
24093 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24094 | + goto done; | |
24095 | + } | |
24096 | + | |
24097 | + val |= WUCSR_BCAST_FR | WUCSR_BCST_EN; | |
24098 | + | |
24099 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24100 | + if (ret < 0) { | |
24101 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24102 | + goto done; | |
24103 | + } | |
24104 | + } | |
24105 | + | |
24106 | + if (pdata->wolopts & WAKE_UCAST) { | |
24107 | + netdev_info(dev->net, "enabling unicast detection\n"); | |
24108 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24109 | + if (ret < 0) { | |
24110 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24111 | + goto done; | |
24112 | + } | |
24113 | + | |
24114 | + val |= WUCSR_WUFR | WUCSR_PFDA_EN; | |
24115 | + | |
24116 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24117 | + if (ret < 0) { | |
24118 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24119 | + goto done; | |
24120 | + } | |
24121 | + } | |
24122 | + | |
24123 | + /* enable receiver to enable frame reception */ | |
24124 | + ret = smsc75xx_read_reg_nopm(dev, MAC_RX, &val); | |
24125 | + if (ret < 0) { | |
24126 | + netdev_warn(dev->net, "Failed to read MAC_RX: %d\n", ret); | |
24127 | + goto done; | |
24128 | + } | |
24129 | + | |
24130 | + val |= MAC_RX_RXEN; | |
24131 | + | |
24132 | + ret = smsc75xx_write_reg_nopm(dev, MAC_RX, val); | |
24133 | + if (ret < 0) { | |
24134 | + netdev_warn(dev->net, "Failed to write MAC_RX: %d\n", ret); | |
24135 | + goto done; | |
24136 | + } | |
24137 | + | |
24138 | + /* some wol options are enabled, so enter SUSPEND0 */ | |
24139 | + netdev_info(dev->net, "entering SUSPEND0 mode\n"); | |
24140 | + ret = smsc75xx_enter_suspend0(dev); | |
24141 | + | |
24142 | +done: | |
24143 | + /* | |
24144 | + * TODO: resume() might need to handle the suspend failure | |
24145 | + * in system sleep | |
24146 | + */ | |
24147 | + if (ret && PMSG_IS_AUTO(message)) | |
24148 | + usbnet_resume(intf); | |
24149 | + return ret; | |
24150 | +} | |
24151 | + | |
24152 | +static int smsc75xx_resume(struct usb_interface *intf) | |
24153 | +{ | |
24154 | + struct usbnet *dev = usb_get_intfdata(intf); | |
24155 | + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | |
24156 | + u8 suspend_flags = pdata->suspend_flags; | |
24157 | + int ret; | |
24158 | + u32 val; | |
24159 | + | |
24160 | + netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags); | |
24161 | + | |
24162 | + /* do this first to ensure it's cleared even in error case */ | |
24163 | + pdata->suspend_flags = 0; | |
24164 | + | |
24165 | + if (suspend_flags & SUSPEND_ALLMODES) { | |
24166 | + /* Disable wakeup sources */ | |
24167 | + ret = smsc75xx_read_reg_nopm(dev, WUCSR, &val); | |
24168 | + if (ret < 0) { | |
24169 | + netdev_warn(dev->net, "Error reading WUCSR\n"); | |
24170 | + return ret; | |
24171 | + } | |
24172 | + | |
24173 | + val &= ~(WUCSR_WUEN | WUCSR_MPEN | WUCSR_PFDA_EN | |
24174 | + | WUCSR_BCST_EN); | |
24175 | + | |
24176 | + ret = smsc75xx_write_reg_nopm(dev, WUCSR, val); | |
24177 | + if (ret < 0) { | |
24178 | + netdev_warn(dev->net, "Error writing WUCSR\n"); | |
24179 | + return ret; | |
24180 | + } | |
24181 | + | |
24182 | + /* clear wake-up status */ | |
24183 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
24184 | + if (ret < 0) { | |
24185 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
24186 | + return ret; | |
24187 | + } | |
24188 | + | |
24189 | + val &= ~PMT_CTL_WOL_EN; | |
24190 | + val |= PMT_CTL_WUPS; | |
24191 | + | |
24192 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
24193 | + if (ret < 0) { | |
24194 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
24195 | + return ret; | |
24196 | + } | |
24197 | + } | |
24198 | + | |
24199 | + if (suspend_flags & SUSPEND_SUSPEND2) { | |
24200 | + netdev_info(dev->net, "resuming from SUSPEND2\n"); | |
24201 | + | |
24202 | + ret = smsc75xx_read_reg_nopm(dev, PMT_CTL, &val); | |
24203 | + if (ret < 0) { | |
24204 | + netdev_warn(dev->net, "Error reading PMT_CTL\n"); | |
24205 | + return ret; | |
24206 | + } | |
24207 | + | |
24208 | + val |= PMT_CTL_PHY_PWRUP; | |
24209 | + | |
24210 | + ret = smsc75xx_write_reg_nopm(dev, PMT_CTL, val); | |
24211 | + if (ret < 0) { | |
24212 | + netdev_warn(dev->net, "Error writing PMT_CTL\n"); | |
24213 | + return ret; | |
24214 | + } | |
24215 | + } | |
24216 | + | |
24217 | + ret = smsc75xx_wait_ready(dev, 1); | |
24218 | + if (ret < 0) { | |
24219 | + netdev_warn(dev->net, "device not ready in smsc75xx_resume\n"); | |
24220 | + return ret; | |
24221 | + } | |
24222 | + | |
24223 | + return usbnet_resume(intf); | |
24224 | +} | |
24225 | + | |
24226 | +static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, | |
24227 | + u32 rx_cmd_a, u32 rx_cmd_b) | |
24228 | +{ | |
24229 | + if (!(dev->net->features & NETIF_F_RXCSUM) || | |
24230 | + unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { | |
24231 | + skb->ip_summed = CHECKSUM_NONE; | |
24232 | + } else { | |
24233 | + skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); | |
24234 | + skb->ip_summed = CHECKSUM_COMPLETE; | |
24235 | + } | |
24236 | +} | |
24237 | + | |
24238 | +static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
24239 | +{ | |
24240 | + /* This check is no longer done by usbnet */ | |
24241 | + if (skb->len < dev->net->hard_header_len) | |
24242 | + return 0; | |
24243 | + | |
24244 | + while (skb->len > 0) { | |
24245 | + u32 rx_cmd_a, rx_cmd_b, align_count, size; | |
24246 | + struct sk_buff *ax_skb; | |
24247 | + unsigned char *packet; | |
24248 | + | |
24249 | + memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a)); | |
24250 | + le32_to_cpus(&rx_cmd_a); | |
24251 | + skb_pull(skb, 4); | |
24252 | + | |
24253 | + memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); | |
24254 | + le32_to_cpus(&rx_cmd_b); | |
24255 | + skb_pull(skb, 4 + RXW_PADDING); | |
24256 | + | |
24257 | + packet = skb->data; | |
24258 | + | |
24259 | + /* get the packet length */ | |
24260 | + size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING; | |
24261 | + align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; | |
24262 | + | |
24263 | + if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { | |
24264 | + netif_dbg(dev, rx_err, dev->net, | |
24265 | + "Error rx_cmd_a=0x%08x\n", rx_cmd_a); | |
24266 | + dev->net->stats.rx_errors++; | |
24267 | + dev->net->stats.rx_dropped++; | |
24268 | + | |
24269 | + if (rx_cmd_a & RX_CMD_A_FCS) | |
24270 | + dev->net->stats.rx_crc_errors++; | |
24271 | + else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT)) | |
24272 | + dev->net->stats.rx_frame_errors++; | |
24273 | + } else { | |
24274 | + /* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */ | |
24275 | + if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) { | |
24276 | + netif_dbg(dev, rx_err, dev->net, | |
24277 | + "size err rx_cmd_a=0x%08x\n", | |
24278 | + rx_cmd_a); | |
24279 | + return 0; | |
24280 | + } | |
24281 | + | |
24282 | + /* last frame in this batch */ | |
24283 | + if (skb->len == size) { | |
24284 | + smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, | |
24285 | + rx_cmd_b); | |
24286 | + | |
24287 | + skb_trim(skb, skb->len - 4); /* remove fcs */ | |
24288 | + skb->truesize = size + sizeof(struct sk_buff); | |
24289 | + | |
24290 | + return 1; | |
24291 | + } | |
24292 | + | |
24293 | + ax_skb = skb_clone(skb, GFP_ATOMIC); | |
24294 | + if (unlikely(!ax_skb)) { | |
24295 | + netdev_warn(dev->net, "Error allocating skb\n"); | |
24296 | + return 0; | |
24297 | + } | |
24298 | + | |
24299 | + ax_skb->len = size; | |
24300 | + ax_skb->data = packet; | |
24301 | + skb_set_tail_pointer(ax_skb, size); | |
24302 | + | |
24303 | + smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, | |
24304 | + rx_cmd_b); | |
24305 | + | |
24306 | + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | |
24307 | + ax_skb->truesize = size + sizeof(struct sk_buff); | |
24308 | + | |
24309 | + usbnet_skb_return(dev, ax_skb); | |
24310 | + } | |
24311 | + | |
24312 | + skb_pull(skb, size); | |
24313 | + | |
24314 | + /* padding bytes before the next frame starts */ | |
24315 | + if (skb->len) | |
24316 | + skb_pull(skb, align_count); | |
24317 | + } | |
24318 | + | |
24319 | + if (unlikely(skb->len < 0)) { | |
24320 | + netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len); | |
24321 | + return 0; | |
24322 | + } | |
24323 | + | |
24324 | + return 1; | |
24325 | +} | |
24326 | + | |
24327 | +static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, | |
24328 | + struct sk_buff *skb, gfp_t flags) | |
24329 | +{ | |
24330 | + u32 tx_cmd_a, tx_cmd_b; | |
24331 | + | |
24332 | + if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { | |
24333 | + struct sk_buff *skb2 = | |
24334 | + skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); | |
24335 | + dev_kfree_skb_any(skb); | |
24336 | + skb = skb2; | |
24337 | + if (!skb) | |
24338 | + return NULL; | |
24339 | + } | |
24340 | + | |
24341 | + tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; | |
24342 | + | |
24343 | + if (skb->ip_summed == CHECKSUM_PARTIAL) | |
24344 | + tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE; | |
24345 | + | |
24346 | + if (skb_is_gso(skb)) { | |
24347 | + u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN); | |
24348 | + tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS; | |
24349 | + | |
24350 | + tx_cmd_a |= TX_CMD_A_LSO; | |
24351 | + } else { | |
24352 | + tx_cmd_b = 0; | |
24353 | + } | |
24354 | + | |
24355 | + skb_push(skb, 4); | |
24356 | + cpu_to_le32s(&tx_cmd_b); | |
24357 | + memcpy(skb->data, &tx_cmd_b, 4); | |
24358 | + | |
24359 | + skb_push(skb, 4); | |
24360 | + cpu_to_le32s(&tx_cmd_a); | |
24361 | + memcpy(skb->data, &tx_cmd_a, 4); | |
24362 | + | |
24363 | + return skb; | |
24364 | +} | |
24365 | + | |
24366 | +static int smsc75xx_manage_power(struct usbnet *dev, int on) | |
24367 | +{ | |
24368 | + dev->intf->needs_remote_wakeup = on; | |
24369 | + return 0; | |
24370 | +} | |
24371 | + | |
24372 | +static const struct driver_info smsc75xx_info = { | |
24373 | + .description = "smsc75xx USB 2.0 Gigabit Ethernet", | |
24374 | + .bind = smsc75xx_bind, | |
24375 | + .unbind = smsc75xx_unbind, | |
24376 | + .link_reset = smsc75xx_link_reset, | |
24377 | + .reset = smsc75xx_reset, | |
24378 | + .rx_fixup = smsc75xx_rx_fixup, | |
24379 | + .tx_fixup = smsc75xx_tx_fixup, | |
24380 | + .status = smsc75xx_status, | |
24381 | + .manage_power = smsc75xx_manage_power, | |
24382 | + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, | |
24383 | +}; | |
24384 | + | |
24385 | +static const struct usb_device_id products[] = { | |
24386 | + { | |
24387 | + /* SMSC7500 USB Gigabit Ethernet Device */ | |
24388 | + USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500), | |
24389 | + .driver_info = (unsigned long) &smsc75xx_info, | |
24390 | + }, | |
24391 | + { | |
24392 | + /* SMSC7500 USB Gigabit Ethernet Device */ | |
24393 | + USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505), | |
24394 | + .driver_info = (unsigned long) &smsc75xx_info, | |
24395 | + }, | |
24396 | + { }, /* END */ | |
24397 | +}; | |
24398 | +MODULE_DEVICE_TABLE(usb, products); | |
24399 | + | |
24400 | +static struct usb_driver smsc75xx_driver = { | |
24401 | + .name = SMSC_CHIPNAME, | |
24402 | + .id_table = products, | |
24403 | + .probe = usbnet_probe, | |
24404 | + .suspend = smsc75xx_suspend, | |
24405 | + .resume = smsc75xx_resume, | |
24406 | + .reset_resume = smsc75xx_resume, | |
24407 | + .disconnect = usbnet_disconnect, | |
24408 | + .disable_hub_initiated_lpm = 1, | |
24409 | + .supports_autosuspend = 1, | |
24410 | +}; | |
24411 | + | |
24412 | +module_usb_driver(smsc75xx_driver); | |
24413 | + | |
24414 | +MODULE_AUTHOR("Nancy Lin"); | |
24415 | +MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>"); | |
24416 | +MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); | |
24417 | +MODULE_LICENSE("GPL"); | |
24418 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/smsc75xx.h backports-3.18.1-1/drivers/net/usb/smsc75xx.h | |
24419 | --- backports-3.18.1-1.org/drivers/net/usb/smsc75xx.h 1970-01-01 01:00:00.000000000 +0100 | |
24420 | +++ backports-3.18.1-1/drivers/net/usb/smsc75xx.h 2014-12-16 18:39:45.000000000 +0100 | |
24421 | @@ -0,0 +1,421 @@ | |
24422 | + /*************************************************************************** | |
24423 | + * | |
24424 | + * Copyright (C) 2007-2010 SMSC | |
24425 | + * | |
24426 | + * This program is free software; you can redistribute it and/or | |
24427 | + * modify it under the terms of the GNU General Public License | |
24428 | + * as published by the Free Software Foundation; either version 2 | |
24429 | + * of the License, or (at your option) any later version. | |
24430 | + * | |
24431 | + * This program is distributed in the hope that it will be useful, | |
24432 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24433 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24434 | + * GNU General Public License for more details. | |
24435 | + * | |
24436 | + * You should have received a copy of the GNU General Public License | |
24437 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
24438 | + * | |
24439 | + *****************************************************************************/ | |
24440 | + | |
24441 | +#ifndef _SMSC75XX_H | |
24442 | +#define _SMSC75XX_H | |
24443 | + | |
24444 | +/* Tx command words */ | |
24445 | +#define TX_CMD_A_LSO (0x08000000) | |
24446 | +#define TX_CMD_A_IPE (0x04000000) | |
24447 | +#define TX_CMD_A_TPE (0x02000000) | |
24448 | +#define TX_CMD_A_IVTG (0x01000000) | |
24449 | +#define TX_CMD_A_RVTG (0x00800000) | |
24450 | +#define TX_CMD_A_FCS (0x00400000) | |
24451 | +#define TX_CMD_A_LEN (0x000FFFFF) | |
24452 | + | |
24453 | +#define TX_CMD_B_MSS (0x3FFF0000) | |
24454 | +#define TX_CMD_B_MSS_SHIFT (16) | |
24455 | +#define TX_MSS_MIN ((u16)8) | |
24456 | +#define TX_CMD_B_VTAG (0x0000FFFF) | |
24457 | + | |
24458 | +/* Rx command words */ | |
24459 | +#define RX_CMD_A_ICE (0x80000000) | |
24460 | +#define RX_CMD_A_TCE (0x40000000) | |
24461 | +#define RX_CMD_A_IPV (0x20000000) | |
24462 | +#define RX_CMD_A_PID (0x18000000) | |
24463 | +#define RX_CMD_A_PID_NIP (0x00000000) | |
24464 | +#define RX_CMD_A_PID_TCP (0x08000000) | |
24465 | +#define RX_CMD_A_PID_UDP (0x10000000) | |
24466 | +#define RX_CMD_A_PID_PP (0x18000000) | |
24467 | +#define RX_CMD_A_PFF (0x04000000) | |
24468 | +#define RX_CMD_A_BAM (0x02000000) | |
24469 | +#define RX_CMD_A_MAM (0x01000000) | |
24470 | +#define RX_CMD_A_FVTG (0x00800000) | |
24471 | +#define RX_CMD_A_RED (0x00400000) | |
24472 | +#define RX_CMD_A_RWT (0x00200000) | |
24473 | +#define RX_CMD_A_RUNT (0x00100000) | |
24474 | +#define RX_CMD_A_LONG (0x00080000) | |
24475 | +#define RX_CMD_A_RXE (0x00040000) | |
24476 | +#define RX_CMD_A_DRB (0x00020000) | |
24477 | +#define RX_CMD_A_FCS (0x00010000) | |
24478 | +#define RX_CMD_A_UAM (0x00008000) | |
24479 | +#define RX_CMD_A_LCSM (0x00004000) | |
24480 | +#define RX_CMD_A_LEN (0x00003FFF) | |
24481 | + | |
24482 | +#define RX_CMD_B_CSUM (0xFFFF0000) | |
24483 | +#define RX_CMD_B_CSUM_SHIFT (16) | |
24484 | +#define RX_CMD_B_VTAG (0x0000FFFF) | |
24485 | + | |
24486 | +/* SCSRs */ | |
24487 | +#define ID_REV (0x0000) | |
24488 | + | |
24489 | +#define FPGA_REV (0x0004) | |
24490 | + | |
24491 | +#define BOND_CTL (0x0008) | |
24492 | + | |
24493 | +#define INT_STS (0x000C) | |
24494 | +#define INT_STS_RDFO_INT (0x00400000) | |
24495 | +#define INT_STS_TXE_INT (0x00200000) | |
24496 | +#define INT_STS_MACRTO_INT (0x00100000) | |
24497 | +#define INT_STS_TX_DIS_INT (0x00080000) | |
24498 | +#define INT_STS_RX_DIS_INT (0x00040000) | |
24499 | +#define INT_STS_PHY_INT_ (0x00020000) | |
24500 | +#define INT_STS_MAC_ERR_INT (0x00008000) | |
24501 | +#define INT_STS_TDFU (0x00004000) | |
24502 | +#define INT_STS_TDFO (0x00002000) | |
24503 | +#define INT_STS_GPIOS (0x00000FFF) | |
24504 | +#define INT_STS_CLEAR_ALL (0xFFFFFFFF) | |
24505 | + | |
24506 | +#define HW_CFG (0x0010) | |
24507 | +#define HW_CFG_SMDET_STS (0x00008000) | |
24508 | +#define HW_CFG_SMDET_EN (0x00004000) | |
24509 | +#define HW_CFG_EEM (0x00002000) | |
24510 | +#define HW_CFG_RST_PROTECT (0x00001000) | |
24511 | +#define HW_CFG_PORT_SWAP (0x00000800) | |
24512 | +#define HW_CFG_PHY_BOOST (0x00000600) | |
24513 | +#define HW_CFG_PHY_BOOST_NORMAL (0x00000000) | |
24514 | +#define HW_CFG_PHY_BOOST_4 (0x00002000) | |
24515 | +#define HW_CFG_PHY_BOOST_8 (0x00004000) | |
24516 | +#define HW_CFG_PHY_BOOST_12 (0x00006000) | |
24517 | +#define HW_CFG_LEDB (0x00000100) | |
24518 | +#define HW_CFG_BIR (0x00000080) | |
24519 | +#define HW_CFG_SBP (0x00000040) | |
24520 | +#define HW_CFG_IME (0x00000020) | |
24521 | +#define HW_CFG_MEF (0x00000010) | |
24522 | +#define HW_CFG_ETC (0x00000008) | |
24523 | +#define HW_CFG_BCE (0x00000004) | |
24524 | +#define HW_CFG_LRST (0x00000002) | |
24525 | +#define HW_CFG_SRST (0x00000001) | |
24526 | + | |
24527 | +#define PMT_CTL (0x0014) | |
24528 | +#define PMT_CTL_PHY_PWRUP (0x00000400) | |
24529 | +#define PMT_CTL_RES_CLR_WKP_EN (0x00000100) | |
24530 | +#define PMT_CTL_DEV_RDY (0x00000080) | |
24531 | +#define PMT_CTL_SUS_MODE (0x00000060) | |
24532 | +#define PMT_CTL_SUS_MODE_0 (0x00000000) | |
24533 | +#define PMT_CTL_SUS_MODE_1 (0x00000020) | |
24534 | +#define PMT_CTL_SUS_MODE_2 (0x00000040) | |
24535 | +#define PMT_CTL_SUS_MODE_3 (0x00000060) | |
24536 | +#define PMT_CTL_PHY_RST (0x00000010) | |
24537 | +#define PMT_CTL_WOL_EN (0x00000008) | |
24538 | +#define PMT_CTL_ED_EN (0x00000004) | |
24539 | +#define PMT_CTL_WUPS (0x00000003) | |
24540 | +#define PMT_CTL_WUPS_NO (0x00000000) | |
24541 | +#define PMT_CTL_WUPS_ED (0x00000001) | |
24542 | +#define PMT_CTL_WUPS_WOL (0x00000002) | |
24543 | +#define PMT_CTL_WUPS_MULTI (0x00000003) | |
24544 | + | |
24545 | +#define LED_GPIO_CFG (0x0018) | |
24546 | +#define LED_GPIO_CFG_LED2_FUN_SEL (0x80000000) | |
24547 | +#define LED_GPIO_CFG_LED10_FUN_SEL (0x40000000) | |
24548 | +#define LED_GPIO_CFG_LEDGPIO_EN (0x0000F000) | |
24549 | +#define LED_GPIO_CFG_LEDGPIO_EN_0 (0x00001000) | |
24550 | +#define LED_GPIO_CFG_LEDGPIO_EN_1 (0x00002000) | |
24551 | +#define LED_GPIO_CFG_LEDGPIO_EN_2 (0x00004000) | |
24552 | +#define LED_GPIO_CFG_LEDGPIO_EN_3 (0x00008000) | |
24553 | +#define LED_GPIO_CFG_GPBUF (0x00000F00) | |
24554 | +#define LED_GPIO_CFG_GPBUF_0 (0x00000100) | |
24555 | +#define LED_GPIO_CFG_GPBUF_1 (0x00000200) | |
24556 | +#define LED_GPIO_CFG_GPBUF_2 (0x00000400) | |
24557 | +#define LED_GPIO_CFG_GPBUF_3 (0x00000800) | |
24558 | +#define LED_GPIO_CFG_GPDIR (0x000000F0) | |
24559 | +#define LED_GPIO_CFG_GPDIR_0 (0x00000010) | |
24560 | +#define LED_GPIO_CFG_GPDIR_1 (0x00000020) | |
24561 | +#define LED_GPIO_CFG_GPDIR_2 (0x00000040) | |
24562 | +#define LED_GPIO_CFG_GPDIR_3 (0x00000080) | |
24563 | +#define LED_GPIO_CFG_GPDATA (0x0000000F) | |
24564 | +#define LED_GPIO_CFG_GPDATA_0 (0x00000001) | |
24565 | +#define LED_GPIO_CFG_GPDATA_1 (0x00000002) | |
24566 | +#define LED_GPIO_CFG_GPDATA_2 (0x00000004) | |
24567 | +#define LED_GPIO_CFG_GPDATA_3 (0x00000008) | |
24568 | + | |
24569 | +#define GPIO_CFG (0x001C) | |
24570 | +#define GPIO_CFG_SHIFT (24) | |
24571 | +#define GPIO_CFG_GPEN (0xFF000000) | |
24572 | +#define GPIO_CFG_GPBUF (0x00FF0000) | |
24573 | +#define GPIO_CFG_GPDIR (0x0000FF00) | |
24574 | +#define GPIO_CFG_GPDATA (0x000000FF) | |
24575 | + | |
24576 | +#define GPIO_WAKE (0x0020) | |
24577 | +#define GPIO_WAKE_PHY_LINKUP_EN (0x80000000) | |
24578 | +#define GPIO_WAKE_POL (0x0FFF0000) | |
24579 | +#define GPIO_WAKE_POL_SHIFT (16) | |
24580 | +#define GPIO_WAKE_WK (0x00000FFF) | |
24581 | + | |
24582 | +#define DP_SEL (0x0024) | |
24583 | +#define DP_SEL_DPRDY (0x80000000) | |
24584 | +#define DP_SEL_RSEL (0x0000000F) | |
24585 | +#define DP_SEL_URX (0x00000000) | |
24586 | +#define DP_SEL_VHF (0x00000001) | |
24587 | +#define DP_SEL_VHF_HASH_LEN (16) | |
24588 | +#define DP_SEL_VHF_VLAN_LEN (128) | |
24589 | +#define DP_SEL_LSO_HEAD (0x00000002) | |
24590 | +#define DP_SEL_FCT_RX (0x00000003) | |
24591 | +#define DP_SEL_FCT_TX (0x00000004) | |
24592 | +#define DP_SEL_DESCRIPTOR (0x00000005) | |
24593 | +#define DP_SEL_WOL (0x00000006) | |
24594 | + | |
24595 | +#define DP_CMD (0x0028) | |
24596 | +#define DP_CMD_WRITE (0x01) | |
24597 | +#define DP_CMD_READ (0x00) | |
24598 | + | |
24599 | +#define DP_ADDR (0x002C) | |
24600 | + | |
24601 | +#define DP_DATA (0x0030) | |
24602 | + | |
24603 | +#define BURST_CAP (0x0034) | |
24604 | +#define BURST_CAP_MASK (0x0000000F) | |
24605 | + | |
24606 | +#define INT_EP_CTL (0x0038) | |
24607 | +#define INT_EP_CTL_INTEP_ON (0x80000000) | |
24608 | +#define INT_EP_CTL_RDFO_EN (0x00400000) | |
24609 | +#define INT_EP_CTL_TXE_EN (0x00200000) | |
24610 | +#define INT_EP_CTL_MACROTO_EN (0x00100000) | |
24611 | +#define INT_EP_CTL_TX_DIS_EN (0x00080000) | |
24612 | +#define INT_EP_CTL_RX_DIS_EN (0x00040000) | |
24613 | +#define INT_EP_CTL_PHY_EN_ (0x00020000) | |
24614 | +#define INT_EP_CTL_MAC_ERR_EN (0x00008000) | |
24615 | +#define INT_EP_CTL_TDFU_EN (0x00004000) | |
24616 | +#define INT_EP_CTL_TDFO_EN (0x00002000) | |
24617 | +#define INT_EP_CTL_RX_FIFO_EN (0x00001000) | |
24618 | +#define INT_EP_CTL_GPIOX_EN (0x00000FFF) | |
24619 | + | |
24620 | +#define BULK_IN_DLY (0x003C) | |
24621 | +#define BULK_IN_DLY_MASK (0xFFFF) | |
24622 | + | |
24623 | +#define E2P_CMD (0x0040) | |
24624 | +#define E2P_CMD_BUSY (0x80000000) | |
24625 | +#define E2P_CMD_MASK (0x70000000) | |
24626 | +#define E2P_CMD_READ (0x00000000) | |
24627 | +#define E2P_CMD_EWDS (0x10000000) | |
24628 | +#define E2P_CMD_EWEN (0x20000000) | |
24629 | +#define E2P_CMD_WRITE (0x30000000) | |
24630 | +#define E2P_CMD_WRAL (0x40000000) | |
24631 | +#define E2P_CMD_ERASE (0x50000000) | |
24632 | +#define E2P_CMD_ERAL (0x60000000) | |
24633 | +#define E2P_CMD_RELOAD (0x70000000) | |
24634 | +#define E2P_CMD_TIMEOUT (0x00000400) | |
24635 | +#define E2P_CMD_LOADED (0x00000200) | |
24636 | +#define E2P_CMD_ADDR (0x000001FF) | |
24637 | + | |
24638 | +#define MAX_EEPROM_SIZE (512) | |
24639 | + | |
24640 | +#define E2P_DATA (0x0044) | |
24641 | +#define E2P_DATA_MASK_ (0x000000FF) | |
24642 | + | |
24643 | +#define RFE_CTL (0x0060) | |
24644 | +#define RFE_CTL_TCPUDP_CKM (0x00001000) | |
24645 | +#define RFE_CTL_IP_CKM (0x00000800) | |
24646 | +#define RFE_CTL_AB (0x00000400) | |
24647 | +#define RFE_CTL_AM (0x00000200) | |
24648 | +#define RFE_CTL_AU (0x00000100) | |
24649 | +#define RFE_CTL_VS (0x00000080) | |
24650 | +#define RFE_CTL_UF (0x00000040) | |
24651 | +#define RFE_CTL_VF (0x00000020) | |
24652 | +#define RFE_CTL_SPF (0x00000010) | |
24653 | +#define RFE_CTL_MHF (0x00000008) | |
24654 | +#define RFE_CTL_DHF (0x00000004) | |
24655 | +#define RFE_CTL_DPF (0x00000002) | |
24656 | +#define RFE_CTL_RST_RF (0x00000001) | |
24657 | + | |
24658 | +#define VLAN_TYPE (0x0064) | |
24659 | +#define VLAN_TYPE_MASK (0x0000FFFF) | |
24660 | + | |
24661 | +#define FCT_RX_CTL (0x0090) | |
24662 | +#define FCT_RX_CTL_EN (0x80000000) | |
24663 | +#define FCT_RX_CTL_RST (0x40000000) | |
24664 | +#define FCT_RX_CTL_SBF (0x02000000) | |
24665 | +#define FCT_RX_CTL_OVERFLOW (0x01000000) | |
24666 | +#define FCT_RX_CTL_FRM_DROP (0x00800000) | |
24667 | +#define FCT_RX_CTL_RX_NOT_EMPTY (0x00400000) | |
24668 | +#define FCT_RX_CTL_RX_EMPTY (0x00200000) | |
24669 | +#define FCT_RX_CTL_RX_DISABLED (0x00100000) | |
24670 | +#define FCT_RX_CTL_RXUSED (0x0000FFFF) | |
24671 | + | |
24672 | +#define FCT_TX_CTL (0x0094) | |
24673 | +#define FCT_TX_CTL_EN (0x80000000) | |
24674 | +#define FCT_TX_CTL_RST (0x40000000) | |
24675 | +#define FCT_TX_CTL_TX_NOT_EMPTY (0x00400000) | |
24676 | +#define FCT_TX_CTL_TX_EMPTY (0x00200000) | |
24677 | +#define FCT_TX_CTL_TX_DISABLED (0x00100000) | |
24678 | +#define FCT_TX_CTL_TXUSED (0x0000FFFF) | |
24679 | + | |
24680 | +#define FCT_RX_FIFO_END (0x0098) | |
24681 | +#define FCT_RX_FIFO_END_MASK (0x0000007F) | |
24682 | + | |
24683 | +#define FCT_TX_FIFO_END (0x009C) | |
24684 | +#define FCT_TX_FIFO_END_MASK (0x0000003F) | |
24685 | + | |
24686 | +#define FCT_FLOW (0x00A0) | |
24687 | +#define FCT_FLOW_THRESHOLD_OFF (0x00007F00) | |
24688 | +#define FCT_FLOW_THRESHOLD_OFF_SHIFT (8) | |
24689 | +#define FCT_FLOW_THRESHOLD_ON (0x0000007F) | |
24690 | + | |
24691 | +/* MAC CSRs */ | |
24692 | +#define MAC_CR (0x100) | |
24693 | +#define MAC_CR_ADP (0x00002000) | |
24694 | +#define MAC_CR_ADD (0x00001000) | |
24695 | +#define MAC_CR_ASD (0x00000800) | |
24696 | +#define MAC_CR_INT_LOOP (0x00000400) | |
24697 | +#define MAC_CR_BOLMT (0x000000C0) | |
24698 | +#define MAC_CR_FDPX (0x00000008) | |
24699 | +#define MAC_CR_CFG (0x00000006) | |
24700 | +#define MAC_CR_CFG_10 (0x00000000) | |
24701 | +#define MAC_CR_CFG_100 (0x00000002) | |
24702 | +#define MAC_CR_CFG_1000 (0x00000004) | |
24703 | +#define MAC_CR_RST (0x00000001) | |
24704 | + | |
24705 | +#define MAC_RX (0x104) | |
24706 | +#define MAC_RX_MAX_SIZE (0x3FFF0000) | |
24707 | +#define MAC_RX_MAX_SIZE_SHIFT (16) | |
24708 | +#define MAC_RX_FCS_STRIP (0x00000010) | |
24709 | +#define MAC_RX_FSE (0x00000004) | |
24710 | +#define MAC_RX_RXD (0x00000002) | |
24711 | +#define MAC_RX_RXEN (0x00000001) | |
24712 | + | |
24713 | +#define MAC_TX (0x108) | |
24714 | +#define MAC_TX_BFCS (0x00000004) | |
24715 | +#define MAC_TX_TXD (0x00000002) | |
24716 | +#define MAC_TX_TXEN (0x00000001) | |
24717 | + | |
24718 | +#define FLOW (0x10C) | |
24719 | +#define FLOW_FORCE_FC (0x80000000) | |
24720 | +#define FLOW_TX_FCEN (0x40000000) | |
24721 | +#define FLOW_RX_FCEN (0x20000000) | |
24722 | +#define FLOW_FPF (0x10000000) | |
24723 | +#define FLOW_PAUSE_TIME (0x0000FFFF) | |
24724 | + | |
24725 | +#define RAND_SEED (0x110) | |
24726 | +#define RAND_SEED_MASK (0x0000FFFF) | |
24727 | + | |
24728 | +#define ERR_STS (0x114) | |
24729 | +#define ERR_STS_FCS_ERR (0x00000100) | |
24730 | +#define ERR_STS_LFRM_ERR (0x00000080) | |
24731 | +#define ERR_STS_RUNT_ERR (0x00000040) | |
24732 | +#define ERR_STS_COLLISION_ERR (0x00000010) | |
24733 | +#define ERR_STS_ALIGN_ERR (0x00000008) | |
24734 | +#define ERR_STS_URUN_ERR (0x00000004) | |
24735 | + | |
24736 | +#define RX_ADDRH (0x118) | |
24737 | +#define RX_ADDRH_MASK (0x0000FFFF) | |
24738 | + | |
24739 | +#define RX_ADDRL (0x11C) | |
24740 | + | |
24741 | +#define MII_ACCESS (0x120) | |
24742 | +#define MII_ACCESS_PHY_ADDR (0x0000F800) | |
24743 | +#define MII_ACCESS_PHY_ADDR_SHIFT (11) | |
24744 | +#define MII_ACCESS_REG_ADDR (0x000007C0) | |
24745 | +#define MII_ACCESS_REG_ADDR_SHIFT (6) | |
24746 | +#define MII_ACCESS_READ (0x00000000) | |
24747 | +#define MII_ACCESS_WRITE (0x00000002) | |
24748 | +#define MII_ACCESS_BUSY (0x00000001) | |
24749 | + | |
24750 | +#define MII_DATA (0x124) | |
24751 | +#define MII_DATA_MASK (0x0000FFFF) | |
24752 | + | |
24753 | +#define WUCSR (0x140) | |
24754 | +#define WUCSR_PFDA_FR (0x00000080) | |
24755 | +#define WUCSR_WUFR (0x00000040) | |
24756 | +#define WUCSR_MPR (0x00000020) | |
24757 | +#define WUCSR_BCAST_FR (0x00000010) | |
24758 | +#define WUCSR_PFDA_EN (0x00000008) | |
24759 | +#define WUCSR_WUEN (0x00000004) | |
24760 | +#define WUCSR_MPEN (0x00000002) | |
24761 | +#define WUCSR_BCST_EN (0x00000001) | |
24762 | + | |
24763 | +#define WUF_CFGX (0x144) | |
24764 | +#define WUF_CFGX_EN (0x80000000) | |
24765 | +#define WUF_CFGX_ATYPE (0x03000000) | |
24766 | +#define WUF_CFGX_ATYPE_UNICAST (0x00000000) | |
24767 | +#define WUF_CFGX_ATYPE_MULTICAST (0x02000000) | |
24768 | +#define WUF_CFGX_ATYPE_ALL (0x03000000) | |
24769 | +#define WUF_CFGX_PATTERN_OFFSET (0x007F0000) | |
24770 | +#define WUF_CFGX_PATTERN_OFFSET_SHIFT (16) | |
24771 | +#define WUF_CFGX_CRC16 (0x0000FFFF) | |
24772 | +#define WUF_NUM (8) | |
24773 | + | |
24774 | +#define WUF_MASKX (0x170) | |
24775 | +#define WUF_MASKX_AVALID (0x80000000) | |
24776 | +#define WUF_MASKX_ATYPE (0x40000000) | |
24777 | + | |
24778 | +#define ADDR_FILTX (0x300) | |
24779 | +#define ADDR_FILTX_FB_VALID (0x80000000) | |
24780 | +#define ADDR_FILTX_FB_TYPE (0x40000000) | |
24781 | +#define ADDR_FILTX_FB_ADDRHI (0x0000FFFF) | |
24782 | +#define ADDR_FILTX_SB_ADDRLO (0xFFFFFFFF) | |
24783 | + | |
24784 | +#define WUCSR2 (0x500) | |
24785 | +#define WUCSR2_NS_RCD (0x00000040) | |
24786 | +#define WUCSR2_ARP_RCD (0x00000020) | |
24787 | +#define WUCSR2_TCPSYN_RCD (0x00000010) | |
24788 | +#define WUCSR2_NS_OFFLOAD (0x00000004) | |
24789 | +#define WUCSR2_ARP_OFFLOAD (0x00000002) | |
24790 | +#define WUCSR2_TCPSYN_OFFLOAD (0x00000001) | |
24791 | + | |
24792 | +#define WOL_FIFO_STS (0x504) | |
24793 | + | |
24794 | +#define IPV6_ADDRX (0x510) | |
24795 | + | |
24796 | +#define IPV4_ADDRX (0x590) | |
24797 | + | |
24798 | + | |
24799 | +/* Vendor-specific PHY Definitions */ | |
24800 | + | |
24801 | +/* Mode Control/Status Register */ | |
24802 | +#define PHY_MODE_CTRL_STS (17) | |
24803 | +#define MODE_CTRL_STS_EDPWRDOWN ((u16)0x2000) | |
24804 | +#define MODE_CTRL_STS_ENERGYON ((u16)0x0002) | |
24805 | + | |
24806 | +#define PHY_INT_SRC (29) | |
24807 | +#define PHY_INT_SRC_ENERGY_ON ((u16)0x0080) | |
24808 | +#define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) | |
24809 | +#define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) | |
24810 | +#define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) | |
24811 | +#define PHY_INT_SRC_CLEAR_ALL ((u16)0xffff) | |
24812 | + | |
24813 | +#define PHY_INT_MASK (30) | |
24814 | +#define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) | |
24815 | +#define PHY_INT_MASK_ANEG_COMP ((u16)0x0040) | |
24816 | +#define PHY_INT_MASK_REMOTE_FAULT ((u16)0x0020) | |
24817 | +#define PHY_INT_MASK_LINK_DOWN ((u16)0x0010) | |
24818 | +#define PHY_INT_MASK_DEFAULT (PHY_INT_MASK_ANEG_COMP | \ | |
24819 | + PHY_INT_MASK_LINK_DOWN) | |
24820 | + | |
24821 | +#define PHY_SPECIAL (31) | |
24822 | +#define PHY_SPECIAL_SPD ((u16)0x001C) | |
24823 | +#define PHY_SPECIAL_SPD_10HALF ((u16)0x0004) | |
24824 | +#define PHY_SPECIAL_SPD_10FULL ((u16)0x0014) | |
24825 | +#define PHY_SPECIAL_SPD_100HALF ((u16)0x0008) | |
24826 | +#define PHY_SPECIAL_SPD_100FULL ((u16)0x0018) | |
24827 | + | |
24828 | +/* USB Vendor Requests */ | |
24829 | +#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 | |
24830 | +#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 | |
24831 | +#define USB_VENDOR_REQUEST_GET_STATS 0xA2 | |
24832 | + | |
24833 | +/* Interrupt Endpoint status word bitfields */ | |
24834 | +#define INT_ENP_RDFO_INT ((u32)BIT(22)) | |
24835 | +#define INT_ENP_TXE_INT ((u32)BIT(21)) | |
24836 | +#define INT_ENP_TX_DIS_INT ((u32)BIT(19)) | |
24837 | +#define INT_ENP_RX_DIS_INT ((u32)BIT(18)) | |
24838 | +#define INT_ENP_PHY_INT ((u32)BIT(17)) | |
24839 | +#define INT_ENP_MAC_ERR_INT ((u32)BIT(15)) | |
24840 | +#define INT_ENP_RX_FIFO_DATA_INT ((u32)BIT(12)) | |
24841 | + | |
24842 | +#endif /* _SMSC75XX_H */ | |
24843 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/smsc95xx.c backports-3.18.1-1/drivers/net/usb/smsc95xx.c | |
24844 | --- backports-3.18.1-1.org/drivers/net/usb/smsc95xx.c 1970-01-01 01:00:00.000000000 +0100 | |
24845 | +++ backports-3.18.1-1/drivers/net/usb/smsc95xx.c 2014-12-16 18:39:45.000000000 +0100 | |
24846 | @@ -0,0 +1,2030 @@ | |
24847 | + /*************************************************************************** | |
24848 | + * | |
24849 | + * Copyright (C) 2007-2008 SMSC | |
24850 | + * | |
24851 | + * This program is free software; you can redistribute it and/or | |
24852 | + * modify it under the terms of the GNU General Public License | |
24853 | + * as published by the Free Software Foundation; either version 2 | |
24854 | + * of the License, or (at your option) any later version. | |
24855 | + * | |
24856 | + * This program is distributed in the hope that it will be useful, | |
24857 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24858 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24859 | + * GNU General Public License for more details. | |
24860 | + * | |
24861 | + * You should have received a copy of the GNU General Public License | |
24862 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
24863 | + * | |
24864 | + *****************************************************************************/ | |
24865 | + | |
24866 | +#include <linux/module.h> | |
24867 | +#include <linux/kmod.h> | |
24868 | +#include <linux/netdevice.h> | |
24869 | +#include <linux/etherdevice.h> | |
24870 | +#include <linux/ethtool.h> | |
24871 | +#include <linux/mii.h> | |
24872 | +#include <linux/usb.h> | |
24873 | +#include <linux/bitrev.h> | |
24874 | +#include <linux/crc16.h> | |
24875 | +#include <linux/crc32.h> | |
24876 | +#include <linux/usb/usbnet.h> | |
24877 | +#include <linux/slab.h> | |
24878 | +#include "smsc95xx.h" | |
24879 | + | |
24880 | +#define SMSC_CHIPNAME "smsc95xx" | |
24881 | +#define SMSC_DRIVER_VERSION "1.0.4" | |
24882 | +#define HS_USB_PKT_SIZE (512) | |
24883 | +#define FS_USB_PKT_SIZE (64) | |
24884 | +#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) | |
24885 | +#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) | |
24886 | +#define DEFAULT_BULK_IN_DELAY (0x00002000) | |
24887 | +#define MAX_SINGLE_PACKET_SIZE (2048) | |
24888 | +#define LAN95XX_EEPROM_MAGIC (0x9500) | |
24889 | +#define EEPROM_MAC_OFFSET (0x01) | |
24890 | +#define DEFAULT_TX_CSUM_ENABLE (true) | |
24891 | +#define DEFAULT_RX_CSUM_ENABLE (true) | |
24892 | +#define SMSC95XX_INTERNAL_PHY_ID (1) | |
24893 | +#define SMSC95XX_TX_OVERHEAD (8) | |
24894 | +#define SMSC95XX_TX_OVERHEAD_CSUM (12) | |
24895 | +#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \ | |
24896 | + WAKE_MCAST | WAKE_ARP | WAKE_MAGIC) | |
24897 | + | |
24898 | +#define FEATURE_8_WAKEUP_FILTERS (0x01) | |
24899 | +#define FEATURE_PHY_NLP_CROSSOVER (0x02) | |
24900 | +#define FEATURE_REMOTE_WAKEUP (0x04) | |
24901 | + | |
24902 | +#define SUSPEND_SUSPEND0 (0x01) | |
24903 | +#define SUSPEND_SUSPEND1 (0x02) | |
24904 | +#define SUSPEND_SUSPEND2 (0x04) | |
24905 | +#define SUSPEND_SUSPEND3 (0x08) | |
24906 | +#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \ | |
24907 | + SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3) | |
24908 | + | |
24909 | +struct smsc95xx_priv { | |
24910 | + u32 mac_cr; | |
24911 | + u32 hash_hi; | |
24912 | + u32 hash_lo; | |
24913 | + u32 wolopts; | |
24914 | + spinlock_t mac_cr_lock; | |
24915 | + u8 features; | |
24916 | + u8 suspend_flags; | |
24917 | +}; | |
24918 | + | |
24919 | +static bool turbo_mode = true; | |
24920 | +module_param(turbo_mode, bool, 0644); | |
24921 | +MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); | |
24922 | + | |
24923 | +static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, | |
24924 | + u32 *data, int in_pm) | |
24925 | +{ | |
24926 | + u32 buf; | |
24927 | + int ret; | |
24928 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16); | |
24929 | + | |
24930 | + BUG_ON(!dev); | |
24931 | + | |
24932 | + if (!in_pm) | |
24933 | + fn = usbnet_read_cmd; | |
24934 | + else | |
24935 | + fn = usbnet_read_cmd_nopm; | |
24936 | + | |
24937 | + ret = fn(dev, USB_VENDOR_REQUEST_READ_REGISTER, USB_DIR_IN | |
24938 | + | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
24939 | + 0, index, &buf, 4); | |
24940 | + if (unlikely(ret < 0)) | |
24941 | + netdev_warn(dev->net, "Failed to read reg index 0x%08x: %d\n", | |
24942 | + index, ret); | |
24943 | + | |
24944 | + le32_to_cpus(&buf); | |
24945 | + *data = buf; | |
24946 | + | |
24947 | + return ret; | |
24948 | +} | |
24949 | + | |
24950 | +static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index, | |
24951 | + u32 data, int in_pm) | |
24952 | +{ | |
24953 | + u32 buf; | |
24954 | + int ret; | |
24955 | + int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16); | |
24956 | + | |
24957 | + BUG_ON(!dev); | |
24958 | + | |
24959 | + if (!in_pm) | |
24960 | + fn = usbnet_write_cmd; | |
24961 | + else | |
24962 | + fn = usbnet_write_cmd_nopm; | |
24963 | + | |
24964 | + buf = data; | |
24965 | + cpu_to_le32s(&buf); | |
24966 | + | |
24967 | + ret = fn(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, USB_DIR_OUT | |
24968 | + | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
24969 | + 0, index, &buf, 4); | |
24970 | + if (unlikely(ret < 0)) | |
24971 | + netdev_warn(dev->net, "Failed to write reg index 0x%08x: %d\n", | |
24972 | + index, ret); | |
24973 | + | |
24974 | + return ret; | |
24975 | +} | |
24976 | + | |
24977 | +static int __must_check smsc95xx_read_reg_nopm(struct usbnet *dev, u32 index, | |
24978 | + u32 *data) | |
24979 | +{ | |
24980 | + return __smsc95xx_read_reg(dev, index, data, 1); | |
24981 | +} | |
24982 | + | |
24983 | +static int __must_check smsc95xx_write_reg_nopm(struct usbnet *dev, u32 index, | |
24984 | + u32 data) | |
24985 | +{ | |
24986 | + return __smsc95xx_write_reg(dev, index, data, 1); | |
24987 | +} | |
24988 | + | |
24989 | +static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index, | |
24990 | + u32 *data) | |
24991 | +{ | |
24992 | + return __smsc95xx_read_reg(dev, index, data, 0); | |
24993 | +} | |
24994 | + | |
24995 | +static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index, | |
24996 | + u32 data) | |
24997 | +{ | |
24998 | + return __smsc95xx_write_reg(dev, index, data, 0); | |
24999 | +} | |
25000 | + | |
25001 | +/* Loop until the read is completed with timeout | |
25002 | + * called with phy_mutex held */ | |
25003 | +static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev, | |
25004 | + int in_pm) | |
25005 | +{ | |
25006 | + unsigned long start_time = jiffies; | |
25007 | + u32 val; | |
25008 | + int ret; | |
25009 | + | |
25010 | + do { | |
25011 | + ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm); | |
25012 | + if (ret < 0) { | |
25013 | + netdev_warn(dev->net, "Error reading MII_ACCESS\n"); | |
25014 | + return ret; | |
25015 | + } | |
25016 | + | |
25017 | + if (!(val & MII_BUSY_)) | |
25018 | + return 0; | |
25019 | + } while (!time_after(jiffies, start_time + HZ)); | |
25020 | + | |
25021 | + return -EIO; | |
25022 | +} | |
25023 | + | |
25024 | +static int __smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx, | |
25025 | + int in_pm) | |
25026 | +{ | |
25027 | + struct usbnet *dev = netdev_priv(netdev); | |
25028 | + u32 val, addr; | |
25029 | + int ret; | |
25030 | + | |
25031 | + mutex_lock(&dev->phy_mutex); | |
25032 | + | |
25033 | + /* confirm MII not busy */ | |
25034 | + ret = __smsc95xx_phy_wait_not_busy(dev, in_pm); | |
25035 | + if (ret < 0) { | |
25036 | + netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n"); | |
25037 | + goto done; | |
25038 | + } | |
25039 | + | |
25040 | + /* set the address, index & direction (read from PHY) */ | |
25041 | + phy_id &= dev->mii.phy_id_mask; | |
25042 | + idx &= dev->mii.reg_num_mask; | |
25043 | + addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_; | |
25044 | + ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); | |
25045 | + if (ret < 0) { | |
25046 | + netdev_warn(dev->net, "Error writing MII_ADDR\n"); | |
25047 | + goto done; | |
25048 | + } | |
25049 | + | |
25050 | + ret = __smsc95xx_phy_wait_not_busy(dev, in_pm); | |
25051 | + if (ret < 0) { | |
25052 | + netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx); | |
25053 | + goto done; | |
25054 | + } | |
25055 | + | |
25056 | + ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm); | |
25057 | + if (ret < 0) { | |
25058 | + netdev_warn(dev->net, "Error reading MII_DATA\n"); | |
25059 | + goto done; | |
25060 | + } | |
25061 | + | |
25062 | + ret = (u16)(val & 0xFFFF); | |
25063 | + | |
25064 | +done: | |
25065 | + mutex_unlock(&dev->phy_mutex); | |
25066 | + return ret; | |
25067 | +} | |
25068 | + | |
25069 | +static void __smsc95xx_mdio_write(struct net_device *netdev, int phy_id, | |
25070 | + int idx, int regval, int in_pm) | |
25071 | +{ | |
25072 | + struct usbnet *dev = netdev_priv(netdev); | |
25073 | + u32 val, addr; | |
25074 | + int ret; | |
25075 | + | |
25076 | + mutex_lock(&dev->phy_mutex); | |
25077 | + | |
25078 | + /* confirm MII not busy */ | |
25079 | + ret = __smsc95xx_phy_wait_not_busy(dev, in_pm); | |
25080 | + if (ret < 0) { | |
25081 | + netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n"); | |
25082 | + goto done; | |
25083 | + } | |
25084 | + | |
25085 | + val = regval; | |
25086 | + ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm); | |
25087 | + if (ret < 0) { | |
25088 | + netdev_warn(dev->net, "Error writing MII_DATA\n"); | |
25089 | + goto done; | |
25090 | + } | |
25091 | + | |
25092 | + /* set the address, index & direction (write to PHY) */ | |
25093 | + phy_id &= dev->mii.phy_id_mask; | |
25094 | + idx &= dev->mii.reg_num_mask; | |
25095 | + addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_; | |
25096 | + ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm); | |
25097 | + if (ret < 0) { | |
25098 | + netdev_warn(dev->net, "Error writing MII_ADDR\n"); | |
25099 | + goto done; | |
25100 | + } | |
25101 | + | |
25102 | + ret = __smsc95xx_phy_wait_not_busy(dev, in_pm); | |
25103 | + if (ret < 0) { | |
25104 | + netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx); | |
25105 | + goto done; | |
25106 | + } | |
25107 | + | |
25108 | +done: | |
25109 | + mutex_unlock(&dev->phy_mutex); | |
25110 | +} | |
25111 | + | |
25112 | +static int smsc95xx_mdio_read_nopm(struct net_device *netdev, int phy_id, | |
25113 | + int idx) | |
25114 | +{ | |
25115 | + return __smsc95xx_mdio_read(netdev, phy_id, idx, 1); | |
25116 | +} | |
25117 | + | |
25118 | +static void smsc95xx_mdio_write_nopm(struct net_device *netdev, int phy_id, | |
25119 | + int idx, int regval) | |
25120 | +{ | |
25121 | + __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 1); | |
25122 | +} | |
25123 | + | |
25124 | +static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx) | |
25125 | +{ | |
25126 | + return __smsc95xx_mdio_read(netdev, phy_id, idx, 0); | |
25127 | +} | |
25128 | + | |
25129 | +static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx, | |
25130 | + int regval) | |
25131 | +{ | |
25132 | + __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 0); | |
25133 | +} | |
25134 | + | |
25135 | +static int __must_check smsc95xx_wait_eeprom(struct usbnet *dev) | |
25136 | +{ | |
25137 | + unsigned long start_time = jiffies; | |
25138 | + u32 val; | |
25139 | + int ret; | |
25140 | + | |
25141 | + do { | |
25142 | + ret = smsc95xx_read_reg(dev, E2P_CMD, &val); | |
25143 | + if (ret < 0) { | |
25144 | + netdev_warn(dev->net, "Error reading E2P_CMD\n"); | |
25145 | + return ret; | |
25146 | + } | |
25147 | + | |
25148 | + if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) | |
25149 | + break; | |
25150 | + udelay(40); | |
25151 | + } while (!time_after(jiffies, start_time + HZ)); | |
25152 | + | |
25153 | + if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { | |
25154 | + netdev_warn(dev->net, "EEPROM read operation timeout\n"); | |
25155 | + return -EIO; | |
25156 | + } | |
25157 | + | |
25158 | + return 0; | |
25159 | +} | |
25160 | + | |
25161 | +static int __must_check smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev) | |
25162 | +{ | |
25163 | + unsigned long start_time = jiffies; | |
25164 | + u32 val; | |
25165 | + int ret; | |
25166 | + | |
25167 | + do { | |
25168 | + ret = smsc95xx_read_reg(dev, E2P_CMD, &val); | |
25169 | + if (ret < 0) { | |
25170 | + netdev_warn(dev->net, "Error reading E2P_CMD\n"); | |
25171 | + return ret; | |
25172 | + } | |
25173 | + | |
25174 | + if (!(val & E2P_CMD_BUSY_)) | |
25175 | + return 0; | |
25176 | + | |
25177 | + udelay(40); | |
25178 | + } while (!time_after(jiffies, start_time + HZ)); | |
25179 | + | |
25180 | + netdev_warn(dev->net, "EEPROM is busy\n"); | |
25181 | + return -EIO; | |
25182 | +} | |
25183 | + | |
25184 | +static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, | |
25185 | + u8 *data) | |
25186 | +{ | |
25187 | + u32 val; | |
25188 | + int i, ret; | |
25189 | + | |
25190 | + BUG_ON(!dev); | |
25191 | + BUG_ON(!data); | |
25192 | + | |
25193 | + ret = smsc95xx_eeprom_confirm_not_busy(dev); | |
25194 | + if (ret) | |
25195 | + return ret; | |
25196 | + | |
25197 | + for (i = 0; i < length; i++) { | |
25198 | + val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); | |
25199 | + ret = smsc95xx_write_reg(dev, E2P_CMD, val); | |
25200 | + if (ret < 0) { | |
25201 | + netdev_warn(dev->net, "Error writing E2P_CMD\n"); | |
25202 | + return ret; | |
25203 | + } | |
25204 | + | |
25205 | + ret = smsc95xx_wait_eeprom(dev); | |
25206 | + if (ret < 0) | |
25207 | + return ret; | |
25208 | + | |
25209 | + ret = smsc95xx_read_reg(dev, E2P_DATA, &val); | |
25210 | + if (ret < 0) { | |
25211 | + netdev_warn(dev->net, "Error reading E2P_DATA\n"); | |
25212 | + return ret; | |
25213 | + } | |
25214 | + | |
25215 | + data[i] = val & 0xFF; | |
25216 | + offset++; | |
25217 | + } | |
25218 | + | |
25219 | + return 0; | |
25220 | +} | |
25221 | + | |
25222 | +static int smsc95xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, | |
25223 | + u8 *data) | |
25224 | +{ | |
25225 | + u32 val; | |
25226 | + int i, ret; | |
25227 | + | |
25228 | + BUG_ON(!dev); | |
25229 | + BUG_ON(!data); | |
25230 | + | |
25231 | + ret = smsc95xx_eeprom_confirm_not_busy(dev); | |
25232 | + if (ret) | |
25233 | + return ret; | |
25234 | + | |
25235 | + /* Issue write/erase enable command */ | |
25236 | + val = E2P_CMD_BUSY_ | E2P_CMD_EWEN_; | |
25237 | + ret = smsc95xx_write_reg(dev, E2P_CMD, val); | |
25238 | + if (ret < 0) { | |
25239 | + netdev_warn(dev->net, "Error writing E2P_DATA\n"); | |
25240 | + return ret; | |
25241 | + } | |
25242 | + | |
25243 | + ret = smsc95xx_wait_eeprom(dev); | |
25244 | + if (ret < 0) | |
25245 | + return ret; | |
25246 | + | |
25247 | + for (i = 0; i < length; i++) { | |
25248 | + | |
25249 | + /* Fill data register */ | |
25250 | + val = data[i]; | |
25251 | + ret = smsc95xx_write_reg(dev, E2P_DATA, val); | |
25252 | + if (ret < 0) { | |
25253 | + netdev_warn(dev->net, "Error writing E2P_DATA\n"); | |
25254 | + return ret; | |
25255 | + } | |
25256 | + | |
25257 | + /* Send "write" command */ | |
25258 | + val = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (offset & E2P_CMD_ADDR_); | |
25259 | + ret = smsc95xx_write_reg(dev, E2P_CMD, val); | |
25260 | + if (ret < 0) { | |
25261 | + netdev_warn(dev->net, "Error writing E2P_CMD\n"); | |
25262 | + return ret; | |
25263 | + } | |
25264 | + | |
25265 | + ret = smsc95xx_wait_eeprom(dev); | |
25266 | + if (ret < 0) | |
25267 | + return ret; | |
25268 | + | |
25269 | + offset++; | |
25270 | + } | |
25271 | + | |
25272 | + return 0; | |
25273 | +} | |
25274 | + | |
25275 | +static int __must_check smsc95xx_write_reg_async(struct usbnet *dev, u16 index, | |
25276 | + u32 data) | |
25277 | +{ | |
25278 | + const u16 size = 4; | |
25279 | + u32 buf; | |
25280 | + int ret; | |
25281 | + | |
25282 | + buf = data; | |
25283 | + cpu_to_le32s(&buf); | |
25284 | + | |
25285 | + ret = usbnet_write_cmd_async(dev, USB_VENDOR_REQUEST_WRITE_REGISTER, | |
25286 | + USB_DIR_OUT | USB_TYPE_VENDOR | | |
25287 | + USB_RECIP_DEVICE, | |
25288 | + 0, index, &buf, size); | |
25289 | + if (ret < 0) | |
25290 | + netdev_warn(dev->net, "Error write async cmd, sts=%d\n", | |
25291 | + ret); | |
25292 | + return ret; | |
25293 | +} | |
25294 | + | |
25295 | +/* returns hash bit number for given MAC address | |
25296 | + * example: | |
25297 | + * 01 00 5E 00 00 01 -> returns bit number 31 */ | |
25298 | +static unsigned int smsc95xx_hash(char addr[ETH_ALEN]) | |
25299 | +{ | |
25300 | + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; | |
25301 | +} | |
25302 | + | |
25303 | +static void smsc95xx_set_multicast(struct net_device *netdev) | |
25304 | +{ | |
25305 | + struct usbnet *dev = netdev_priv(netdev); | |
25306 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25307 | + unsigned long flags; | |
25308 | + int ret; | |
25309 | + | |
25310 | + pdata->hash_hi = 0; | |
25311 | + pdata->hash_lo = 0; | |
25312 | + | |
25313 | + spin_lock_irqsave(&pdata->mac_cr_lock, flags); | |
25314 | + | |
25315 | + if (dev->net->flags & IFF_PROMISC) { | |
25316 | + netif_dbg(dev, drv, dev->net, "promiscuous mode enabled\n"); | |
25317 | + pdata->mac_cr |= MAC_CR_PRMS_; | |
25318 | + pdata->mac_cr &= ~(MAC_CR_MCPAS_ | MAC_CR_HPFILT_); | |
25319 | + } else if (dev->net->flags & IFF_ALLMULTI) { | |
25320 | + netif_dbg(dev, drv, dev->net, "receive all multicast enabled\n"); | |
25321 | + pdata->mac_cr |= MAC_CR_MCPAS_; | |
25322 | + pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_); | |
25323 | + } else if (!netdev_mc_empty(dev->net)) { | |
25324 | + struct netdev_hw_addr *ha; | |
25325 | + | |
25326 | + pdata->mac_cr |= MAC_CR_HPFILT_; | |
25327 | + pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_); | |
25328 | + | |
25329 | + netdev_for_each_mc_addr(ha, netdev) { | |
25330 | + u32 bitnum = smsc95xx_hash(ha->addr); | |
25331 | + u32 mask = 0x01 << (bitnum & 0x1F); | |
25332 | + if (bitnum & 0x20) | |
25333 | + pdata->hash_hi |= mask; | |
25334 | + else | |
25335 | + pdata->hash_lo |= mask; | |
25336 | + } | |
25337 | + | |
25338 | + netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", | |
25339 | + pdata->hash_hi, pdata->hash_lo); | |
25340 | + } else { | |
25341 | + netif_dbg(dev, drv, dev->net, "receive own packets only\n"); | |
25342 | + pdata->mac_cr &= | |
25343 | + ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); | |
25344 | + } | |
25345 | + | |
25346 | + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | |
25347 | + | |
25348 | + /* Initiate async writes, as we can't wait for completion here */ | |
25349 | + ret = smsc95xx_write_reg_async(dev, HASHH, pdata->hash_hi); | |
25350 | + if (ret < 0) | |
25351 | + netdev_warn(dev->net, "failed to initiate async write to HASHH\n"); | |
25352 | + | |
25353 | + ret = smsc95xx_write_reg_async(dev, HASHL, pdata->hash_lo); | |
25354 | + if (ret < 0) | |
25355 | + netdev_warn(dev->net, "failed to initiate async write to HASHL\n"); | |
25356 | + | |
25357 | + ret = smsc95xx_write_reg_async(dev, MAC_CR, pdata->mac_cr); | |
25358 | + if (ret < 0) | |
25359 | + netdev_warn(dev->net, "failed to initiate async write to MAC_CR\n"); | |
25360 | +} | |
25361 | + | |
25362 | +static int smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, | |
25363 | + u16 lcladv, u16 rmtadv) | |
25364 | +{ | |
25365 | + u32 flow, afc_cfg = 0; | |
25366 | + | |
25367 | + int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg); | |
25368 | + if (ret < 0) | |
25369 | + return ret; | |
25370 | + | |
25371 | + if (duplex == DUPLEX_FULL) { | |
25372 | + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); | |
25373 | + | |
25374 | + if (cap & FLOW_CTRL_RX) | |
25375 | + flow = 0xFFFF0002; | |
25376 | + else | |
25377 | + flow = 0; | |
25378 | + | |
25379 | + if (cap & FLOW_CTRL_TX) | |
25380 | + afc_cfg |= 0xF; | |
25381 | + else | |
25382 | + afc_cfg &= ~0xF; | |
25383 | + | |
25384 | + netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n", | |
25385 | + cap & FLOW_CTRL_RX ? "enabled" : "disabled", | |
25386 | + cap & FLOW_CTRL_TX ? "enabled" : "disabled"); | |
25387 | + } else { | |
25388 | + netif_dbg(dev, link, dev->net, "half duplex\n"); | |
25389 | + flow = 0; | |
25390 | + afc_cfg |= 0xF; | |
25391 | + } | |
25392 | + | |
25393 | + ret = smsc95xx_write_reg(dev, FLOW, flow); | |
25394 | + if (ret < 0) | |
25395 | + return ret; | |
25396 | + | |
25397 | + return smsc95xx_write_reg(dev, AFC_CFG, afc_cfg); | |
25398 | +} | |
25399 | + | |
25400 | +static int smsc95xx_link_reset(struct usbnet *dev) | |
25401 | +{ | |
25402 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25403 | + struct mii_if_info *mii = &dev->mii; | |
25404 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
25405 | + unsigned long flags; | |
25406 | + u16 lcladv, rmtadv; | |
25407 | + int ret; | |
25408 | + | |
25409 | + /* clear interrupt status */ | |
25410 | + ret = smsc95xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); | |
25411 | + if (ret < 0) | |
25412 | + return ret; | |
25413 | + | |
25414 | + ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_); | |
25415 | + if (ret < 0) | |
25416 | + return ret; | |
25417 | + | |
25418 | + mii_check_media(mii, 1, 1); | |
25419 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
25420 | + lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); | |
25421 | + rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); | |
25422 | + | |
25423 | + netif_dbg(dev, link, dev->net, | |
25424 | + "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", | |
25425 | + ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); | |
25426 | + | |
25427 | + spin_lock_irqsave(&pdata->mac_cr_lock, flags); | |
25428 | + if (ecmd.duplex != DUPLEX_FULL) { | |
25429 | + pdata->mac_cr &= ~MAC_CR_FDPX_; | |
25430 | + pdata->mac_cr |= MAC_CR_RCVOWN_; | |
25431 | + } else { | |
25432 | + pdata->mac_cr &= ~MAC_CR_RCVOWN_; | |
25433 | + pdata->mac_cr |= MAC_CR_FDPX_; | |
25434 | + } | |
25435 | + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | |
25436 | + | |
25437 | + ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); | |
25438 | + if (ret < 0) | |
25439 | + return ret; | |
25440 | + | |
25441 | + ret = smsc95xx_phy_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); | |
25442 | + if (ret < 0) | |
25443 | + netdev_warn(dev->net, "Error updating PHY flow control\n"); | |
25444 | + | |
25445 | + return ret; | |
25446 | +} | |
25447 | + | |
25448 | +static void smsc95xx_status(struct usbnet *dev, struct urb *urb) | |
25449 | +{ | |
25450 | + u32 intdata; | |
25451 | + | |
25452 | + if (urb->actual_length != 4) { | |
25453 | + netdev_warn(dev->net, "unexpected urb length %d\n", | |
25454 | + urb->actual_length); | |
25455 | + return; | |
25456 | + } | |
25457 | + | |
25458 | + memcpy(&intdata, urb->transfer_buffer, 4); | |
25459 | + le32_to_cpus(&intdata); | |
25460 | + | |
25461 | + netif_dbg(dev, link, dev->net, "intdata: 0x%08X\n", intdata); | |
25462 | + | |
25463 | + if (intdata & INT_ENP_PHY_INT_) | |
25464 | + usbnet_defer_kevent(dev, EVENT_LINK_RESET); | |
25465 | + else | |
25466 | + netdev_warn(dev->net, "unexpected interrupt, intdata=0x%08X\n", | |
25467 | + intdata); | |
25468 | +} | |
25469 | + | |
25470 | +/* Enable or disable Tx & Rx checksum offload engines */ | |
25471 | +static int smsc95xx_set_features(struct net_device *netdev, | |
25472 | + netdev_features_t features) | |
25473 | +{ | |
25474 | + struct usbnet *dev = netdev_priv(netdev); | |
25475 | + u32 read_buf; | |
25476 | + int ret; | |
25477 | + | |
25478 | + ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | |
25479 | + if (ret < 0) | |
25480 | + return ret; | |
25481 | + | |
25482 | + if (features & NETIF_F_HW_CSUM) | |
25483 | + read_buf |= Tx_COE_EN_; | |
25484 | + else | |
25485 | + read_buf &= ~Tx_COE_EN_; | |
25486 | + | |
25487 | + if (features & NETIF_F_RXCSUM) | |
25488 | + read_buf |= Rx_COE_EN_; | |
25489 | + else | |
25490 | + read_buf &= ~Rx_COE_EN_; | |
25491 | + | |
25492 | + ret = smsc95xx_write_reg(dev, COE_CR, read_buf); | |
25493 | + if (ret < 0) | |
25494 | + return ret; | |
25495 | + | |
25496 | + netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf); | |
25497 | + return 0; | |
25498 | +} | |
25499 | + | |
25500 | +static int smsc95xx_ethtool_get_eeprom_len(struct net_device *net) | |
25501 | +{ | |
25502 | + return MAX_EEPROM_SIZE; | |
25503 | +} | |
25504 | + | |
25505 | +static int smsc95xx_ethtool_get_eeprom(struct net_device *netdev, | |
25506 | + struct ethtool_eeprom *ee, u8 *data) | |
25507 | +{ | |
25508 | + struct usbnet *dev = netdev_priv(netdev); | |
25509 | + | |
25510 | + ee->magic = LAN95XX_EEPROM_MAGIC; | |
25511 | + | |
25512 | + return smsc95xx_read_eeprom(dev, ee->offset, ee->len, data); | |
25513 | +} | |
25514 | + | |
25515 | +static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, | |
25516 | + struct ethtool_eeprom *ee, u8 *data) | |
25517 | +{ | |
25518 | + struct usbnet *dev = netdev_priv(netdev); | |
25519 | + | |
25520 | + if (ee->magic != LAN95XX_EEPROM_MAGIC) { | |
25521 | + netdev_warn(dev->net, "EEPROM: magic value mismatch, magic = 0x%x\n", | |
25522 | + ee->magic); | |
25523 | + return -EINVAL; | |
25524 | + } | |
25525 | + | |
25526 | + return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); | |
25527 | +} | |
25528 | + | |
25529 | +static int smsc95xx_ethtool_getregslen(struct net_device *netdev) | |
25530 | +{ | |
25531 | + /* all smsc95xx registers */ | |
25532 | + return COE_CR - ID_REV + sizeof(u32); | |
25533 | +} | |
25534 | + | |
25535 | +static void | |
25536 | +smsc95xx_ethtool_getregs(struct net_device *netdev, struct ethtool_regs *regs, | |
25537 | + void *buf) | |
25538 | +{ | |
25539 | + struct usbnet *dev = netdev_priv(netdev); | |
25540 | + unsigned int i, j; | |
25541 | + int retval; | |
25542 | + u32 *data = buf; | |
25543 | + | |
25544 | + retval = smsc95xx_read_reg(dev, ID_REV, ®s->version); | |
25545 | + if (retval < 0) { | |
25546 | + netdev_warn(netdev, "REGS: cannot read ID_REV\n"); | |
25547 | + return; | |
25548 | + } | |
25549 | + | |
25550 | + for (i = ID_REV, j = 0; i <= COE_CR; i += (sizeof(u32)), j++) { | |
25551 | + retval = smsc95xx_read_reg(dev, i, &data[j]); | |
25552 | + if (retval < 0) { | |
25553 | + netdev_warn(netdev, "REGS: cannot read reg[%x]\n", i); | |
25554 | + return; | |
25555 | + } | |
25556 | + } | |
25557 | +} | |
25558 | + | |
25559 | +static void smsc95xx_ethtool_get_wol(struct net_device *net, | |
25560 | + struct ethtool_wolinfo *wolinfo) | |
25561 | +{ | |
25562 | + struct usbnet *dev = netdev_priv(net); | |
25563 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25564 | + | |
25565 | + wolinfo->supported = SUPPORTED_WAKE; | |
25566 | + wolinfo->wolopts = pdata->wolopts; | |
25567 | +} | |
25568 | + | |
25569 | +static int smsc95xx_ethtool_set_wol(struct net_device *net, | |
25570 | + struct ethtool_wolinfo *wolinfo) | |
25571 | +{ | |
25572 | + struct usbnet *dev = netdev_priv(net); | |
25573 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25574 | + int ret; | |
25575 | + | |
25576 | + pdata->wolopts = wolinfo->wolopts & SUPPORTED_WAKE; | |
25577 | + | |
25578 | + ret = device_set_wakeup_enable(&dev->udev->dev, pdata->wolopts); | |
25579 | + if (ret < 0) | |
25580 | + netdev_warn(dev->net, "device_set_wakeup_enable error %d\n", ret); | |
25581 | + | |
25582 | + return ret; | |
25583 | +} | |
25584 | + | |
25585 | +static const struct ethtool_ops smsc95xx_ethtool_ops = { | |
25586 | + .get_link = usbnet_get_link, | |
25587 | + .nway_reset = usbnet_nway_reset, | |
25588 | + .get_drvinfo = usbnet_get_drvinfo, | |
25589 | + .get_msglevel = usbnet_get_msglevel, | |
25590 | + .set_msglevel = usbnet_set_msglevel, | |
25591 | + .get_settings = usbnet_get_settings, | |
25592 | + .set_settings = usbnet_set_settings, | |
25593 | + .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, | |
25594 | + .get_eeprom = smsc95xx_ethtool_get_eeprom, | |
25595 | + .set_eeprom = smsc95xx_ethtool_set_eeprom, | |
25596 | + .get_regs_len = smsc95xx_ethtool_getregslen, | |
25597 | + .get_regs = smsc95xx_ethtool_getregs, | |
25598 | + .get_wol = smsc95xx_ethtool_get_wol, | |
25599 | + .set_wol = smsc95xx_ethtool_set_wol, | |
25600 | +}; | |
25601 | + | |
25602 | +static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
25603 | +{ | |
25604 | + struct usbnet *dev = netdev_priv(netdev); | |
25605 | + | |
25606 | + if (!netif_running(netdev)) | |
25607 | + return -EINVAL; | |
25608 | + | |
25609 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
25610 | +} | |
25611 | + | |
25612 | +static void smsc95xx_init_mac_address(struct usbnet *dev) | |
25613 | +{ | |
25614 | + /* try reading mac address from EEPROM */ | |
25615 | + if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, | |
25616 | + dev->net->dev_addr) == 0) { | |
25617 | + if (is_valid_ether_addr(dev->net->dev_addr)) { | |
25618 | + /* eeprom values are valid so use them */ | |
25619 | + netif_dbg(dev, ifup, dev->net, "MAC address read from EEPROM\n"); | |
25620 | + return; | |
25621 | + } | |
25622 | + } | |
25623 | + | |
25624 | + /* no eeprom, or eeprom values are invalid. generate random MAC */ | |
25625 | + eth_hw_addr_random(dev->net); | |
25626 | + netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); | |
25627 | +} | |
25628 | + | |
25629 | +static int smsc95xx_set_mac_address(struct usbnet *dev) | |
25630 | +{ | |
25631 | + u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | | |
25632 | + dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; | |
25633 | + u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; | |
25634 | + int ret; | |
25635 | + | |
25636 | + ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); | |
25637 | + if (ret < 0) | |
25638 | + return ret; | |
25639 | + | |
25640 | + return smsc95xx_write_reg(dev, ADDRH, addr_hi); | |
25641 | +} | |
25642 | + | |
25643 | +/* starts the TX path */ | |
25644 | +static int smsc95xx_start_tx_path(struct usbnet *dev) | |
25645 | +{ | |
25646 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25647 | + unsigned long flags; | |
25648 | + int ret; | |
25649 | + | |
25650 | + /* Enable Tx at MAC */ | |
25651 | + spin_lock_irqsave(&pdata->mac_cr_lock, flags); | |
25652 | + pdata->mac_cr |= MAC_CR_TXEN_; | |
25653 | + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | |
25654 | + | |
25655 | + ret = smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr); | |
25656 | + if (ret < 0) | |
25657 | + return ret; | |
25658 | + | |
25659 | + /* Enable Tx at SCSRs */ | |
25660 | + return smsc95xx_write_reg(dev, TX_CFG, TX_CFG_ON_); | |
25661 | +} | |
25662 | + | |
25663 | +/* Starts the Receive path */ | |
25664 | +static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm) | |
25665 | +{ | |
25666 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25667 | + unsigned long flags; | |
25668 | + | |
25669 | + spin_lock_irqsave(&pdata->mac_cr_lock, flags); | |
25670 | + pdata->mac_cr |= MAC_CR_RXEN_; | |
25671 | + spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | |
25672 | + | |
25673 | + return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm); | |
25674 | +} | |
25675 | + | |
25676 | +static int smsc95xx_phy_initialize(struct usbnet *dev) | |
25677 | +{ | |
25678 | + int bmcr, ret, timeout = 0; | |
25679 | + | |
25680 | + /* Initialize MII structure */ | |
25681 | + dev->mii.dev = dev->net; | |
25682 | + dev->mii.mdio_read = smsc95xx_mdio_read; | |
25683 | + dev->mii.mdio_write = smsc95xx_mdio_write; | |
25684 | + dev->mii.phy_id_mask = 0x1f; | |
25685 | + dev->mii.reg_num_mask = 0x1f; | |
25686 | + dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID; | |
25687 | + | |
25688 | + /* reset phy and wait for reset to complete */ | |
25689 | + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
25690 | + | |
25691 | + do { | |
25692 | + msleep(10); | |
25693 | + bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); | |
25694 | + timeout++; | |
25695 | + } while ((bmcr & BMCR_RESET) && (timeout < 100)); | |
25696 | + | |
25697 | + if (timeout >= 100) { | |
25698 | + netdev_warn(dev->net, "timeout on PHY Reset"); | |
25699 | + return -EIO; | |
25700 | + } | |
25701 | + | |
25702 | + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
25703 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | | |
25704 | + ADVERTISE_PAUSE_ASYM); | |
25705 | + | |
25706 | + /* read to clear */ | |
25707 | + ret = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); | |
25708 | + if (ret < 0) { | |
25709 | + netdev_warn(dev->net, "Failed to read PHY_INT_SRC during init\n"); | |
25710 | + return ret; | |
25711 | + } | |
25712 | + | |
25713 | + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, | |
25714 | + PHY_INT_MASK_DEFAULT_); | |
25715 | + mii_nway_restart(&dev->mii); | |
25716 | + | |
25717 | + netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n"); | |
25718 | + return 0; | |
25719 | +} | |
25720 | + | |
25721 | +static int smsc95xx_reset(struct usbnet *dev) | |
25722 | +{ | |
25723 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25724 | + u32 read_buf, write_buf, burst_cap; | |
25725 | + int ret = 0, timeout; | |
25726 | + | |
25727 | + netif_dbg(dev, ifup, dev->net, "entering smsc95xx_reset\n"); | |
25728 | + | |
25729 | + ret = smsc95xx_write_reg(dev, HW_CFG, HW_CFG_LRST_); | |
25730 | + if (ret < 0) | |
25731 | + return ret; | |
25732 | + | |
25733 | + timeout = 0; | |
25734 | + do { | |
25735 | + msleep(10); | |
25736 | + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); | |
25737 | + if (ret < 0) | |
25738 | + return ret; | |
25739 | + timeout++; | |
25740 | + } while ((read_buf & HW_CFG_LRST_) && (timeout < 100)); | |
25741 | + | |
25742 | + if (timeout >= 100) { | |
25743 | + netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n"); | |
25744 | + return ret; | |
25745 | + } | |
25746 | + | |
25747 | + ret = smsc95xx_write_reg(dev, PM_CTRL, PM_CTL_PHY_RST_); | |
25748 | + if (ret < 0) | |
25749 | + return ret; | |
25750 | + | |
25751 | + timeout = 0; | |
25752 | + do { | |
25753 | + msleep(10); | |
25754 | + ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); | |
25755 | + if (ret < 0) | |
25756 | + return ret; | |
25757 | + timeout++; | |
25758 | + } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); | |
25759 | + | |
25760 | + if (timeout >= 100) { | |
25761 | + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); | |
25762 | + return ret; | |
25763 | + } | |
25764 | + | |
25765 | + ret = smsc95xx_set_mac_address(dev); | |
25766 | + if (ret < 0) | |
25767 | + return ret; | |
25768 | + | |
25769 | + netif_dbg(dev, ifup, dev->net, "MAC Address: %pM\n", | |
25770 | + dev->net->dev_addr); | |
25771 | + | |
25772 | + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); | |
25773 | + if (ret < 0) | |
25774 | + return ret; | |
25775 | + | |
25776 | + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x\n", | |
25777 | + read_buf); | |
25778 | + | |
25779 | + read_buf |= HW_CFG_BIR_; | |
25780 | + | |
25781 | + ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); | |
25782 | + if (ret < 0) | |
25783 | + return ret; | |
25784 | + | |
25785 | + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); | |
25786 | + if (ret < 0) | |
25787 | + return ret; | |
25788 | + | |
25789 | + netif_dbg(dev, ifup, dev->net, | |
25790 | + "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n", | |
25791 | + read_buf); | |
25792 | + | |
25793 | + if (!turbo_mode) { | |
25794 | + burst_cap = 0; | |
25795 | + dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; | |
25796 | + } else if (dev->udev->speed == USB_SPEED_HIGH) { | |
25797 | + burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; | |
25798 | + dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; | |
25799 | + } else { | |
25800 | + burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; | |
25801 | + dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; | |
25802 | + } | |
25803 | + | |
25804 | + netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", | |
25805 | + (ulong)dev->rx_urb_size); | |
25806 | + | |
25807 | + ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); | |
25808 | + if (ret < 0) | |
25809 | + return ret; | |
25810 | + | |
25811 | + ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); | |
25812 | + if (ret < 0) | |
25813 | + return ret; | |
25814 | + | |
25815 | + netif_dbg(dev, ifup, dev->net, | |
25816 | + "Read Value from BURST_CAP after writing: 0x%08x\n", | |
25817 | + read_buf); | |
25818 | + | |
25819 | + ret = smsc95xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); | |
25820 | + if (ret < 0) | |
25821 | + return ret; | |
25822 | + | |
25823 | + ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); | |
25824 | + if (ret < 0) | |
25825 | + return ret; | |
25826 | + | |
25827 | + netif_dbg(dev, ifup, dev->net, | |
25828 | + "Read Value from BULK_IN_DLY after writing: 0x%08x\n", | |
25829 | + read_buf); | |
25830 | + | |
25831 | + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); | |
25832 | + if (ret < 0) | |
25833 | + return ret; | |
25834 | + | |
25835 | + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG: 0x%08x\n", | |
25836 | + read_buf); | |
25837 | + | |
25838 | + if (turbo_mode) | |
25839 | + read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_); | |
25840 | + | |
25841 | + read_buf &= ~HW_CFG_RXDOFF_; | |
25842 | + | |
25843 | + /* set Rx data offset=2, Make IP header aligns on word boundary. */ | |
25844 | + read_buf |= NET_IP_ALIGN << 9; | |
25845 | + | |
25846 | + ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); | |
25847 | + if (ret < 0) | |
25848 | + return ret; | |
25849 | + | |
25850 | + ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); | |
25851 | + if (ret < 0) | |
25852 | + return ret; | |
25853 | + | |
25854 | + netif_dbg(dev, ifup, dev->net, | |
25855 | + "Read Value from HW_CFG after writing: 0x%08x\n", read_buf); | |
25856 | + | |
25857 | + ret = smsc95xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_); | |
25858 | + if (ret < 0) | |
25859 | + return ret; | |
25860 | + | |
25861 | + ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); | |
25862 | + if (ret < 0) | |
25863 | + return ret; | |
25864 | + netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf); | |
25865 | + | |
25866 | + /* Configure GPIO pins as LED outputs */ | |
25867 | + write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | | |
25868 | + LED_GPIO_CFG_FDX_LED; | |
25869 | + ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); | |
25870 | + if (ret < 0) | |
25871 | + return ret; | |
25872 | + | |
25873 | + /* Init Tx */ | |
25874 | + ret = smsc95xx_write_reg(dev, FLOW, 0); | |
25875 | + if (ret < 0) | |
25876 | + return ret; | |
25877 | + | |
25878 | + ret = smsc95xx_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT); | |
25879 | + if (ret < 0) | |
25880 | + return ret; | |
25881 | + | |
25882 | + /* Don't need mac_cr_lock during initialisation */ | |
25883 | + ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr); | |
25884 | + if (ret < 0) | |
25885 | + return ret; | |
25886 | + | |
25887 | + /* Init Rx */ | |
25888 | + /* Set Vlan */ | |
25889 | + ret = smsc95xx_write_reg(dev, VLAN1, (u32)ETH_P_8021Q); | |
25890 | + if (ret < 0) | |
25891 | + return ret; | |
25892 | + | |
25893 | + /* Enable or disable checksum offload engines */ | |
25894 | + ret = smsc95xx_set_features(dev->net, dev->net->features); | |
25895 | + if (ret < 0) { | |
25896 | + netdev_warn(dev->net, "Failed to set checksum offload features\n"); | |
25897 | + return ret; | |
25898 | + } | |
25899 | + | |
25900 | + smsc95xx_set_multicast(dev->net); | |
25901 | + | |
25902 | + ret = smsc95xx_phy_initialize(dev); | |
25903 | + if (ret < 0) { | |
25904 | + netdev_warn(dev->net, "Failed to init PHY\n"); | |
25905 | + return ret; | |
25906 | + } | |
25907 | + | |
25908 | + ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); | |
25909 | + if (ret < 0) | |
25910 | + return ret; | |
25911 | + | |
25912 | + /* enable PHY interrupts */ | |
25913 | + read_buf |= INT_EP_CTL_PHY_INT_; | |
25914 | + | |
25915 | + ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); | |
25916 | + if (ret < 0) | |
25917 | + return ret; | |
25918 | + | |
25919 | + ret = smsc95xx_start_tx_path(dev); | |
25920 | + if (ret < 0) { | |
25921 | + netdev_warn(dev->net, "Failed to start TX path\n"); | |
25922 | + return ret; | |
25923 | + } | |
25924 | + | |
25925 | + ret = smsc95xx_start_rx_path(dev, 0); | |
25926 | + if (ret < 0) { | |
25927 | + netdev_warn(dev->net, "Failed to start RX path\n"); | |
25928 | + return ret; | |
25929 | + } | |
25930 | + | |
25931 | + netif_dbg(dev, ifup, dev->net, "smsc95xx_reset, return 0\n"); | |
25932 | + return 0; | |
25933 | +} | |
25934 | + | |
25935 | +static const struct net_device_ops smsc95xx_netdev_ops = { | |
25936 | + .ndo_open = usbnet_open, | |
25937 | + .ndo_stop = usbnet_stop, | |
25938 | + .ndo_start_xmit = usbnet_start_xmit, | |
25939 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
25940 | + .ndo_change_mtu = usbnet_change_mtu, | |
25941 | + .ndo_set_mac_address = eth_mac_addr, | |
25942 | + .ndo_validate_addr = eth_validate_addr, | |
25943 | + .ndo_do_ioctl = smsc95xx_ioctl, | |
25944 | + .ndo_set_rx_mode = smsc95xx_set_multicast, | |
25945 | + .ndo_set_features = smsc95xx_set_features, | |
25946 | +}; | |
25947 | + | |
25948 | +static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |
25949 | +{ | |
25950 | + struct smsc95xx_priv *pdata = NULL; | |
25951 | + u32 val; | |
25952 | + int ret; | |
25953 | + | |
25954 | + printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); | |
25955 | + | |
25956 | + ret = usbnet_get_endpoints(dev, intf); | |
25957 | + if (ret < 0) { | |
25958 | + netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret); | |
25959 | + return ret; | |
25960 | + } | |
25961 | + | |
25962 | + dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc95xx_priv), | |
25963 | + GFP_KERNEL); | |
25964 | + | |
25965 | + pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
25966 | + if (!pdata) | |
25967 | + return -ENOMEM; | |
25968 | + | |
25969 | + spin_lock_init(&pdata->mac_cr_lock); | |
25970 | + | |
25971 | + if (DEFAULT_TX_CSUM_ENABLE) | |
25972 | + dev->net->features |= NETIF_F_HW_CSUM; | |
25973 | + if (DEFAULT_RX_CSUM_ENABLE) | |
25974 | + dev->net->features |= NETIF_F_RXCSUM; | |
25975 | + | |
25976 | + dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; | |
25977 | + | |
25978 | + smsc95xx_init_mac_address(dev); | |
25979 | + | |
25980 | + /* Init all registers */ | |
25981 | + ret = smsc95xx_reset(dev); | |
25982 | + | |
25983 | + /* detect device revision as different features may be available */ | |
25984 | + ret = smsc95xx_read_reg(dev, ID_REV, &val); | |
25985 | + if (ret < 0) | |
25986 | + return ret; | |
25987 | + val >>= 16; | |
25988 | + | |
25989 | + if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9530_) || | |
25990 | + (val == ID_REV_CHIP_ID_89530_) || (val == ID_REV_CHIP_ID_9730_)) | |
25991 | + pdata->features = (FEATURE_8_WAKEUP_FILTERS | | |
25992 | + FEATURE_PHY_NLP_CROSSOVER | | |
25993 | + FEATURE_REMOTE_WAKEUP); | |
25994 | + else if (val == ID_REV_CHIP_ID_9512_) | |
25995 | + pdata->features = FEATURE_8_WAKEUP_FILTERS; | |
25996 | + | |
25997 | + dev->net->netdev_ops = &smsc95xx_netdev_ops; | |
25998 | + dev->net->ethtool_ops = &smsc95xx_ethtool_ops; | |
25999 | + dev->net->flags |= IFF_MULTICAST; | |
26000 | + dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; | |
26001 | + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | |
26002 | + return 0; | |
26003 | +} | |
26004 | + | |
26005 | +static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf) | |
26006 | +{ | |
26007 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26008 | + if (pdata) { | |
26009 | + netif_dbg(dev, ifdown, dev->net, "free pdata\n"); | |
26010 | + kfree(pdata); | |
26011 | + pdata = NULL; | |
26012 | + dev->data[0] = 0; | |
26013 | + } | |
26014 | +} | |
26015 | + | |
26016 | +static u32 smsc_crc(const u8 *buffer, size_t len, int filter) | |
26017 | +{ | |
26018 | + u32 crc = bitrev16(crc16(0xFFFF, buffer, len)); | |
26019 | + return crc << ((filter % 2) * 16); | |
26020 | +} | |
26021 | + | |
26022 | +static int smsc95xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask) | |
26023 | +{ | |
26024 | + struct mii_if_info *mii = &dev->mii; | |
26025 | + int ret; | |
26026 | + | |
26027 | + netdev_dbg(dev->net, "enabling PHY wakeup interrupts\n"); | |
26028 | + | |
26029 | + /* read to clear */ | |
26030 | + ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC); | |
26031 | + if (ret < 0) | |
26032 | + return ret; | |
26033 | + | |
26034 | + /* enable interrupt source */ | |
26035 | + ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK); | |
26036 | + if (ret < 0) | |
26037 | + return ret; | |
26038 | + | |
26039 | + ret |= mask; | |
26040 | + | |
26041 | + smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret); | |
26042 | + | |
26043 | + return 0; | |
26044 | +} | |
26045 | + | |
26046 | +static int smsc95xx_link_ok_nopm(struct usbnet *dev) | |
26047 | +{ | |
26048 | + struct mii_if_info *mii = &dev->mii; | |
26049 | + int ret; | |
26050 | + | |
26051 | + /* first, a dummy read, needed to latch some MII phys */ | |
26052 | + ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR); | |
26053 | + if (ret < 0) | |
26054 | + return ret; | |
26055 | + | |
26056 | + ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR); | |
26057 | + if (ret < 0) | |
26058 | + return ret; | |
26059 | + | |
26060 | + return !!(ret & BMSR_LSTATUS); | |
26061 | +} | |
26062 | + | |
26063 | +static int smsc95xx_enter_suspend0(struct usbnet *dev) | |
26064 | +{ | |
26065 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26066 | + u32 val; | |
26067 | + int ret; | |
26068 | + | |
26069 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26070 | + if (ret < 0) | |
26071 | + return ret; | |
26072 | + | |
26073 | + val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_)); | |
26074 | + val |= PM_CTL_SUS_MODE_0; | |
26075 | + | |
26076 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26077 | + if (ret < 0) | |
26078 | + return ret; | |
26079 | + | |
26080 | + /* clear wol status */ | |
26081 | + val &= ~PM_CTL_WUPS_; | |
26082 | + val |= PM_CTL_WUPS_WOL_; | |
26083 | + | |
26084 | + /* enable energy detection */ | |
26085 | + if (pdata->wolopts & WAKE_PHY) | |
26086 | + val |= PM_CTL_WUPS_ED_; | |
26087 | + | |
26088 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26089 | + if (ret < 0) | |
26090 | + return ret; | |
26091 | + | |
26092 | + /* read back PM_CTRL */ | |
26093 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26094 | + if (ret < 0) | |
26095 | + return ret; | |
26096 | + | |
26097 | + pdata->suspend_flags |= SUSPEND_SUSPEND0; | |
26098 | + | |
26099 | + return 0; | |
26100 | +} | |
26101 | + | |
26102 | +static int smsc95xx_enter_suspend1(struct usbnet *dev) | |
26103 | +{ | |
26104 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26105 | + struct mii_if_info *mii = &dev->mii; | |
26106 | + u32 val; | |
26107 | + int ret; | |
26108 | + | |
26109 | + /* reconfigure link pulse detection timing for | |
26110 | + * compatibility with non-standard link partners | |
26111 | + */ | |
26112 | + if (pdata->features & FEATURE_PHY_NLP_CROSSOVER) | |
26113 | + smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_EDPD_CONFIG, | |
26114 | + PHY_EDPD_CONFIG_DEFAULT); | |
26115 | + | |
26116 | + /* enable energy detect power-down mode */ | |
26117 | + ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS); | |
26118 | + if (ret < 0) | |
26119 | + return ret; | |
26120 | + | |
26121 | + ret |= MODE_CTRL_STS_EDPWRDOWN_; | |
26122 | + | |
26123 | + smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_MODE_CTRL_STS, ret); | |
26124 | + | |
26125 | + /* enter SUSPEND1 mode */ | |
26126 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26127 | + if (ret < 0) | |
26128 | + return ret; | |
26129 | + | |
26130 | + val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_); | |
26131 | + val |= PM_CTL_SUS_MODE_1; | |
26132 | + | |
26133 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26134 | + if (ret < 0) | |
26135 | + return ret; | |
26136 | + | |
26137 | + /* clear wol status, enable energy detection */ | |
26138 | + val &= ~PM_CTL_WUPS_; | |
26139 | + val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_); | |
26140 | + | |
26141 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26142 | + if (ret < 0) | |
26143 | + return ret; | |
26144 | + | |
26145 | + pdata->suspend_flags |= SUSPEND_SUSPEND1; | |
26146 | + | |
26147 | + return 0; | |
26148 | +} | |
26149 | + | |
26150 | +static int smsc95xx_enter_suspend2(struct usbnet *dev) | |
26151 | +{ | |
26152 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26153 | + u32 val; | |
26154 | + int ret; | |
26155 | + | |
26156 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26157 | + if (ret < 0) | |
26158 | + return ret; | |
26159 | + | |
26160 | + val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_); | |
26161 | + val |= PM_CTL_SUS_MODE_2; | |
26162 | + | |
26163 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26164 | + if (ret < 0) | |
26165 | + return ret; | |
26166 | + | |
26167 | + pdata->suspend_flags |= SUSPEND_SUSPEND2; | |
26168 | + | |
26169 | + return 0; | |
26170 | +} | |
26171 | + | |
26172 | +static int smsc95xx_enter_suspend3(struct usbnet *dev) | |
26173 | +{ | |
26174 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26175 | + u32 val; | |
26176 | + int ret; | |
26177 | + | |
26178 | + ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val); | |
26179 | + if (ret < 0) | |
26180 | + return ret; | |
26181 | + | |
26182 | + if (val & 0xFFFF) { | |
26183 | + netdev_info(dev->net, "rx fifo not empty in autosuspend\n"); | |
26184 | + return -EBUSY; | |
26185 | + } | |
26186 | + | |
26187 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26188 | + if (ret < 0) | |
26189 | + return ret; | |
26190 | + | |
26191 | + val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_); | |
26192 | + val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS; | |
26193 | + | |
26194 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26195 | + if (ret < 0) | |
26196 | + return ret; | |
26197 | + | |
26198 | + /* clear wol status */ | |
26199 | + val &= ~PM_CTL_WUPS_; | |
26200 | + val |= PM_CTL_WUPS_WOL_; | |
26201 | + | |
26202 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26203 | + if (ret < 0) | |
26204 | + return ret; | |
26205 | + | |
26206 | + pdata->suspend_flags |= SUSPEND_SUSPEND3; | |
26207 | + | |
26208 | + return 0; | |
26209 | +} | |
26210 | + | |
26211 | +static int smsc95xx_autosuspend(struct usbnet *dev, u32 link_up) | |
26212 | +{ | |
26213 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26214 | + int ret; | |
26215 | + | |
26216 | + if (!netif_running(dev->net)) { | |
26217 | + /* interface is ifconfig down so fully power down hw */ | |
26218 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND2\n"); | |
26219 | + return smsc95xx_enter_suspend2(dev); | |
26220 | + } | |
26221 | + | |
26222 | + if (!link_up) { | |
26223 | + /* link is down so enter EDPD mode, but only if device can | |
26224 | + * reliably resume from it. This check should be redundant | |
26225 | + * as current FEATURE_REMOTE_WAKEUP parts also support | |
26226 | + * FEATURE_PHY_NLP_CROSSOVER but it's included for clarity */ | |
26227 | + if (!(pdata->features & FEATURE_PHY_NLP_CROSSOVER)) { | |
26228 | + netdev_warn(dev->net, "EDPD not supported\n"); | |
26229 | + return -EBUSY; | |
26230 | + } | |
26231 | + | |
26232 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND1\n"); | |
26233 | + | |
26234 | + /* enable PHY wakeup events for if cable is attached */ | |
26235 | + ret = smsc95xx_enable_phy_wakeup_interrupts(dev, | |
26236 | + PHY_INT_MASK_ANEG_COMP_); | |
26237 | + if (ret < 0) { | |
26238 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
26239 | + return ret; | |
26240 | + } | |
26241 | + | |
26242 | + netdev_info(dev->net, "entering SUSPEND1 mode\n"); | |
26243 | + return smsc95xx_enter_suspend1(dev); | |
26244 | + } | |
26245 | + | |
26246 | + /* enable PHY wakeup events so we remote wakeup if cable is pulled */ | |
26247 | + ret = smsc95xx_enable_phy_wakeup_interrupts(dev, | |
26248 | + PHY_INT_MASK_LINK_DOWN_); | |
26249 | + if (ret < 0) { | |
26250 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
26251 | + return ret; | |
26252 | + } | |
26253 | + | |
26254 | + netdev_dbg(dev->net, "autosuspend entering SUSPEND3\n"); | |
26255 | + return smsc95xx_enter_suspend3(dev); | |
26256 | +} | |
26257 | + | |
26258 | +static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) | |
26259 | +{ | |
26260 | + struct usbnet *dev = usb_get_intfdata(intf); | |
26261 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26262 | + u32 val, link_up; | |
26263 | + int ret; | |
26264 | + | |
26265 | + ret = usbnet_suspend(intf, message); | |
26266 | + if (ret < 0) { | |
26267 | + netdev_warn(dev->net, "usbnet_suspend error\n"); | |
26268 | + return ret; | |
26269 | + } | |
26270 | + | |
26271 | + if (pdata->suspend_flags) { | |
26272 | + netdev_warn(dev->net, "error during last resume\n"); | |
26273 | + pdata->suspend_flags = 0; | |
26274 | + } | |
26275 | + | |
26276 | + /* determine if link is up using only _nopm functions */ | |
26277 | + link_up = smsc95xx_link_ok_nopm(dev); | |
26278 | + | |
26279 | + if (message.event == PM_EVENT_AUTO_SUSPEND && | |
26280 | + (pdata->features & FEATURE_REMOTE_WAKEUP)) { | |
26281 | + ret = smsc95xx_autosuspend(dev, link_up); | |
26282 | + goto done; | |
26283 | + } | |
26284 | + | |
26285 | + /* if we get this far we're not autosuspending */ | |
26286 | + /* if no wol options set, or if link is down and we're not waking on | |
26287 | + * PHY activity, enter lowest power SUSPEND2 mode | |
26288 | + */ | |
26289 | + if (!(pdata->wolopts & SUPPORTED_WAKE) || | |
26290 | + !(link_up || (pdata->wolopts & WAKE_PHY))) { | |
26291 | + netdev_info(dev->net, "entering SUSPEND2 mode\n"); | |
26292 | + | |
26293 | + /* disable energy detect (link up) & wake up events */ | |
26294 | + ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | |
26295 | + if (ret < 0) | |
26296 | + goto done; | |
26297 | + | |
26298 | + val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_); | |
26299 | + | |
26300 | + ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | |
26301 | + if (ret < 0) | |
26302 | + goto done; | |
26303 | + | |
26304 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26305 | + if (ret < 0) | |
26306 | + goto done; | |
26307 | + | |
26308 | + val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_); | |
26309 | + | |
26310 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26311 | + if (ret < 0) | |
26312 | + goto done; | |
26313 | + | |
26314 | + ret = smsc95xx_enter_suspend2(dev); | |
26315 | + goto done; | |
26316 | + } | |
26317 | + | |
26318 | + if (pdata->wolopts & WAKE_PHY) { | |
26319 | + ret = smsc95xx_enable_phy_wakeup_interrupts(dev, | |
26320 | + (PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_)); | |
26321 | + if (ret < 0) { | |
26322 | + netdev_warn(dev->net, "error enabling PHY wakeup ints\n"); | |
26323 | + goto done; | |
26324 | + } | |
26325 | + | |
26326 | + /* if link is down then configure EDPD and enter SUSPEND1, | |
26327 | + * otherwise enter SUSPEND0 below | |
26328 | + */ | |
26329 | + if (!link_up) { | |
26330 | + netdev_info(dev->net, "entering SUSPEND1 mode\n"); | |
26331 | + ret = smsc95xx_enter_suspend1(dev); | |
26332 | + goto done; | |
26333 | + } | |
26334 | + } | |
26335 | + | |
26336 | + if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { | |
26337 | + u32 *filter_mask = kzalloc(sizeof(u32) * 32, GFP_KERNEL); | |
26338 | + u32 command[2]; | |
26339 | + u32 offset[2]; | |
26340 | + u32 crc[4]; | |
26341 | + int wuff_filter_count = | |
26342 | + (pdata->features & FEATURE_8_WAKEUP_FILTERS) ? | |
26343 | + LAN9500A_WUFF_NUM : LAN9500_WUFF_NUM; | |
26344 | + int i, filter = 0; | |
26345 | + | |
26346 | + if (!filter_mask) { | |
26347 | + netdev_warn(dev->net, "Unable to allocate filter_mask\n"); | |
26348 | + ret = -ENOMEM; | |
26349 | + goto done; | |
26350 | + } | |
26351 | + | |
26352 | + memset(command, 0, sizeof(command)); | |
26353 | + memset(offset, 0, sizeof(offset)); | |
26354 | + memset(crc, 0, sizeof(crc)); | |
26355 | + | |
26356 | + if (pdata->wolopts & WAKE_BCAST) { | |
26357 | + const u8 bcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |
26358 | + netdev_info(dev->net, "enabling broadcast detection\n"); | |
26359 | + filter_mask[filter * 4] = 0x003F; | |
26360 | + filter_mask[filter * 4 + 1] = 0x00; | |
26361 | + filter_mask[filter * 4 + 2] = 0x00; | |
26362 | + filter_mask[filter * 4 + 3] = 0x00; | |
26363 | + command[filter/4] |= 0x05UL << ((filter % 4) * 8); | |
26364 | + offset[filter/4] |= 0x00 << ((filter % 4) * 8); | |
26365 | + crc[filter/2] |= smsc_crc(bcast, 6, filter); | |
26366 | + filter++; | |
26367 | + } | |
26368 | + | |
26369 | + if (pdata->wolopts & WAKE_MCAST) { | |
26370 | + const u8 mcast[] = {0x01, 0x00, 0x5E}; | |
26371 | + netdev_info(dev->net, "enabling multicast detection\n"); | |
26372 | + filter_mask[filter * 4] = 0x0007; | |
26373 | + filter_mask[filter * 4 + 1] = 0x00; | |
26374 | + filter_mask[filter * 4 + 2] = 0x00; | |
26375 | + filter_mask[filter * 4 + 3] = 0x00; | |
26376 | + command[filter/4] |= 0x09UL << ((filter % 4) * 8); | |
26377 | + offset[filter/4] |= 0x00 << ((filter % 4) * 8); | |
26378 | + crc[filter/2] |= smsc_crc(mcast, 3, filter); | |
26379 | + filter++; | |
26380 | + } | |
26381 | + | |
26382 | + if (pdata->wolopts & WAKE_ARP) { | |
26383 | + const u8 arp[] = {0x08, 0x06}; | |
26384 | + netdev_info(dev->net, "enabling ARP detection\n"); | |
26385 | + filter_mask[filter * 4] = 0x0003; | |
26386 | + filter_mask[filter * 4 + 1] = 0x00; | |
26387 | + filter_mask[filter * 4 + 2] = 0x00; | |
26388 | + filter_mask[filter * 4 + 3] = 0x00; | |
26389 | + command[filter/4] |= 0x05UL << ((filter % 4) * 8); | |
26390 | + offset[filter/4] |= 0x0C << ((filter % 4) * 8); | |
26391 | + crc[filter/2] |= smsc_crc(arp, 2, filter); | |
26392 | + filter++; | |
26393 | + } | |
26394 | + | |
26395 | + if (pdata->wolopts & WAKE_UCAST) { | |
26396 | + netdev_info(dev->net, "enabling unicast detection\n"); | |
26397 | + filter_mask[filter * 4] = 0x003F; | |
26398 | + filter_mask[filter * 4 + 1] = 0x00; | |
26399 | + filter_mask[filter * 4 + 2] = 0x00; | |
26400 | + filter_mask[filter * 4 + 3] = 0x00; | |
26401 | + command[filter/4] |= 0x01UL << ((filter % 4) * 8); | |
26402 | + offset[filter/4] |= 0x00 << ((filter % 4) * 8); | |
26403 | + crc[filter/2] |= smsc_crc(dev->net->dev_addr, ETH_ALEN, filter); | |
26404 | + filter++; | |
26405 | + } | |
26406 | + | |
26407 | + for (i = 0; i < (wuff_filter_count * 4); i++) { | |
26408 | + ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]); | |
26409 | + if (ret < 0) { | |
26410 | + kfree(filter_mask); | |
26411 | + goto done; | |
26412 | + } | |
26413 | + } | |
26414 | + kfree(filter_mask); | |
26415 | + | |
26416 | + for (i = 0; i < (wuff_filter_count / 4); i++) { | |
26417 | + ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]); | |
26418 | + if (ret < 0) | |
26419 | + goto done; | |
26420 | + } | |
26421 | + | |
26422 | + for (i = 0; i < (wuff_filter_count / 4); i++) { | |
26423 | + ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]); | |
26424 | + if (ret < 0) | |
26425 | + goto done; | |
26426 | + } | |
26427 | + | |
26428 | + for (i = 0; i < (wuff_filter_count / 2); i++) { | |
26429 | + ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]); | |
26430 | + if (ret < 0) | |
26431 | + goto done; | |
26432 | + } | |
26433 | + | |
26434 | + /* clear any pending pattern match packet status */ | |
26435 | + ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | |
26436 | + if (ret < 0) | |
26437 | + goto done; | |
26438 | + | |
26439 | + val |= WUCSR_WUFR_; | |
26440 | + | |
26441 | + ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | |
26442 | + if (ret < 0) | |
26443 | + goto done; | |
26444 | + } | |
26445 | + | |
26446 | + if (pdata->wolopts & WAKE_MAGIC) { | |
26447 | + /* clear any pending magic packet status */ | |
26448 | + ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | |
26449 | + if (ret < 0) | |
26450 | + goto done; | |
26451 | + | |
26452 | + val |= WUCSR_MPR_; | |
26453 | + | |
26454 | + ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | |
26455 | + if (ret < 0) | |
26456 | + goto done; | |
26457 | + } | |
26458 | + | |
26459 | + /* enable/disable wakeup sources */ | |
26460 | + ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | |
26461 | + if (ret < 0) | |
26462 | + goto done; | |
26463 | + | |
26464 | + if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { | |
26465 | + netdev_info(dev->net, "enabling pattern match wakeup\n"); | |
26466 | + val |= WUCSR_WAKE_EN_; | |
26467 | + } else { | |
26468 | + netdev_info(dev->net, "disabling pattern match wakeup\n"); | |
26469 | + val &= ~WUCSR_WAKE_EN_; | |
26470 | + } | |
26471 | + | |
26472 | + if (pdata->wolopts & WAKE_MAGIC) { | |
26473 | + netdev_info(dev->net, "enabling magic packet wakeup\n"); | |
26474 | + val |= WUCSR_MPEN_; | |
26475 | + } else { | |
26476 | + netdev_info(dev->net, "disabling magic packet wakeup\n"); | |
26477 | + val &= ~WUCSR_MPEN_; | |
26478 | + } | |
26479 | + | |
26480 | + ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | |
26481 | + if (ret < 0) | |
26482 | + goto done; | |
26483 | + | |
26484 | + /* enable wol wakeup source */ | |
26485 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26486 | + if (ret < 0) | |
26487 | + goto done; | |
26488 | + | |
26489 | + val |= PM_CTL_WOL_EN_; | |
26490 | + | |
26491 | + /* phy energy detect wakeup source */ | |
26492 | + if (pdata->wolopts & WAKE_PHY) | |
26493 | + val |= PM_CTL_ED_EN_; | |
26494 | + | |
26495 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26496 | + if (ret < 0) | |
26497 | + goto done; | |
26498 | + | |
26499 | + /* enable receiver to enable frame reception */ | |
26500 | + smsc95xx_start_rx_path(dev, 1); | |
26501 | + | |
26502 | + /* some wol options are enabled, so enter SUSPEND0 */ | |
26503 | + netdev_info(dev->net, "entering SUSPEND0 mode\n"); | |
26504 | + ret = smsc95xx_enter_suspend0(dev); | |
26505 | + | |
26506 | +done: | |
26507 | + /* | |
26508 | + * TODO: resume() might need to handle the suspend failure | |
26509 | + * in system sleep | |
26510 | + */ | |
26511 | + if (ret && PMSG_IS_AUTO(message)) | |
26512 | + usbnet_resume(intf); | |
26513 | + return ret; | |
26514 | +} | |
26515 | + | |
26516 | +static int smsc95xx_resume(struct usb_interface *intf) | |
26517 | +{ | |
26518 | + struct usbnet *dev = usb_get_intfdata(intf); | |
26519 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26520 | + u8 suspend_flags = pdata->suspend_flags; | |
26521 | + int ret; | |
26522 | + u32 val; | |
26523 | + | |
26524 | + BUG_ON(!dev); | |
26525 | + | |
26526 | + netdev_dbg(dev->net, "resume suspend_flags=0x%02x\n", suspend_flags); | |
26527 | + | |
26528 | + /* do this first to ensure it's cleared even in error case */ | |
26529 | + pdata->suspend_flags = 0; | |
26530 | + | |
26531 | + if (suspend_flags & SUSPEND_ALLMODES) { | |
26532 | + /* clear wake-up sources */ | |
26533 | + ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val); | |
26534 | + if (ret < 0) | |
26535 | + return ret; | |
26536 | + | |
26537 | + val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_); | |
26538 | + | |
26539 | + ret = smsc95xx_write_reg_nopm(dev, WUCSR, val); | |
26540 | + if (ret < 0) | |
26541 | + return ret; | |
26542 | + | |
26543 | + /* clear wake-up status */ | |
26544 | + ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val); | |
26545 | + if (ret < 0) | |
26546 | + return ret; | |
26547 | + | |
26548 | + val &= ~PM_CTL_WOL_EN_; | |
26549 | + val |= PM_CTL_WUPS_; | |
26550 | + | |
26551 | + ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); | |
26552 | + if (ret < 0) | |
26553 | + return ret; | |
26554 | + } | |
26555 | + | |
26556 | + ret = usbnet_resume(intf); | |
26557 | + if (ret < 0) | |
26558 | + netdev_warn(dev->net, "usbnet_resume error\n"); | |
26559 | + | |
26560 | + return ret; | |
26561 | +} | |
26562 | + | |
26563 | +static int smsc95xx_reset_resume(struct usb_interface *intf) | |
26564 | +{ | |
26565 | + struct usbnet *dev = usb_get_intfdata(intf); | |
26566 | + int ret; | |
26567 | + | |
26568 | + ret = smsc95xx_reset(dev); | |
26569 | + if (ret < 0) | |
26570 | + return ret; | |
26571 | + | |
26572 | + return smsc95xx_resume(intf); | |
26573 | +} | |
26574 | + | |
26575 | +static void smsc95xx_rx_csum_offload(struct sk_buff *skb) | |
26576 | +{ | |
26577 | + skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); | |
26578 | + skb->ip_summed = CHECKSUM_COMPLETE; | |
26579 | + skb_trim(skb, skb->len - 2); | |
26580 | +} | |
26581 | + | |
26582 | +static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
26583 | +{ | |
26584 | + /* This check is no longer done by usbnet */ | |
26585 | + if (skb->len < dev->net->hard_header_len) | |
26586 | + return 0; | |
26587 | + | |
26588 | + while (skb->len > 0) { | |
26589 | + u32 header, align_count; | |
26590 | + struct sk_buff *ax_skb; | |
26591 | + unsigned char *packet; | |
26592 | + u16 size; | |
26593 | + | |
26594 | + memcpy(&header, skb->data, sizeof(header)); | |
26595 | + le32_to_cpus(&header); | |
26596 | + skb_pull(skb, 4 + NET_IP_ALIGN); | |
26597 | + packet = skb->data; | |
26598 | + | |
26599 | + /* get the packet length */ | |
26600 | + size = (u16)((header & RX_STS_FL_) >> 16); | |
26601 | + align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; | |
26602 | + | |
26603 | + if (unlikely(header & RX_STS_ES_)) { | |
26604 | + netif_dbg(dev, rx_err, dev->net, | |
26605 | + "Error header=0x%08x\n", header); | |
26606 | + dev->net->stats.rx_errors++; | |
26607 | + dev->net->stats.rx_dropped++; | |
26608 | + | |
26609 | + if (header & RX_STS_CRC_) { | |
26610 | + dev->net->stats.rx_crc_errors++; | |
26611 | + } else { | |
26612 | + if (header & (RX_STS_TL_ | RX_STS_RF_)) | |
26613 | + dev->net->stats.rx_frame_errors++; | |
26614 | + | |
26615 | + if ((header & RX_STS_LE_) && | |
26616 | + (!(header & RX_STS_FT_))) | |
26617 | + dev->net->stats.rx_length_errors++; | |
26618 | + } | |
26619 | + } else { | |
26620 | + /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ | |
26621 | + if (unlikely(size > (ETH_FRAME_LEN + 12))) { | |
26622 | + netif_dbg(dev, rx_err, dev->net, | |
26623 | + "size err header=0x%08x\n", header); | |
26624 | + return 0; | |
26625 | + } | |
26626 | + | |
26627 | + /* last frame in this batch */ | |
26628 | + if (skb->len == size) { | |
26629 | + if (dev->net->features & NETIF_F_RXCSUM) | |
26630 | + smsc95xx_rx_csum_offload(skb); | |
26631 | + skb_trim(skb, skb->len - 4); /* remove fcs */ | |
26632 | + skb->truesize = size + sizeof(struct sk_buff); | |
26633 | + | |
26634 | + return 1; | |
26635 | + } | |
26636 | + | |
26637 | + ax_skb = skb_clone(skb, GFP_ATOMIC); | |
26638 | + if (unlikely(!ax_skb)) { | |
26639 | + netdev_warn(dev->net, "Error allocating skb\n"); | |
26640 | + return 0; | |
26641 | + } | |
26642 | + | |
26643 | + ax_skb->len = size; | |
26644 | + ax_skb->data = packet; | |
26645 | + skb_set_tail_pointer(ax_skb, size); | |
26646 | + | |
26647 | + if (dev->net->features & NETIF_F_RXCSUM) | |
26648 | + smsc95xx_rx_csum_offload(ax_skb); | |
26649 | + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | |
26650 | + ax_skb->truesize = size + sizeof(struct sk_buff); | |
26651 | + | |
26652 | + usbnet_skb_return(dev, ax_skb); | |
26653 | + } | |
26654 | + | |
26655 | + skb_pull(skb, size); | |
26656 | + | |
26657 | + /* padding bytes before the next frame starts */ | |
26658 | + if (skb->len) | |
26659 | + skb_pull(skb, align_count); | |
26660 | + } | |
26661 | + | |
26662 | + if (unlikely(skb->len < 0)) { | |
26663 | + netdev_warn(dev->net, "invalid rx length<0 %d\n", skb->len); | |
26664 | + return 0; | |
26665 | + } | |
26666 | + | |
26667 | + return 1; | |
26668 | +} | |
26669 | + | |
26670 | +static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) | |
26671 | +{ | |
26672 | + u16 low_16 = (u16)skb_checksum_start_offset(skb); | |
26673 | + u16 high_16 = low_16 + skb->csum_offset; | |
26674 | + return (high_16 << 16) | low_16; | |
26675 | +} | |
26676 | + | |
26677 | +static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | |
26678 | + struct sk_buff *skb, gfp_t flags) | |
26679 | +{ | |
26680 | + bool csum = skb->ip_summed == CHECKSUM_PARTIAL; | |
26681 | + int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; | |
26682 | + u32 tx_cmd_a, tx_cmd_b; | |
26683 | + | |
26684 | + /* We do not advertise SG, so skbs should be already linearized */ | |
26685 | + BUG_ON(skb_shinfo(skb)->nr_frags); | |
26686 | + | |
26687 | + if (skb_headroom(skb) < overhead) { | |
26688 | + struct sk_buff *skb2 = skb_copy_expand(skb, | |
26689 | + overhead, 0, flags); | |
26690 | + dev_kfree_skb_any(skb); | |
26691 | + skb = skb2; | |
26692 | + if (!skb) | |
26693 | + return NULL; | |
26694 | + } | |
26695 | + | |
26696 | + if (csum) { | |
26697 | + if (skb->len <= 45) { | |
26698 | + /* workaround - hardware tx checksum does not work | |
26699 | + * properly with extremely small packets */ | |
26700 | + long csstart = skb_checksum_start_offset(skb); | |
26701 | + __wsum calc = csum_partial(skb->data + csstart, | |
26702 | + skb->len - csstart, 0); | |
26703 | + *((__sum16 *)(skb->data + csstart | |
26704 | + + skb->csum_offset)) = csum_fold(calc); | |
26705 | + | |
26706 | + csum = false; | |
26707 | + } else { | |
26708 | + u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); | |
26709 | + skb_push(skb, 4); | |
26710 | + cpu_to_le32s(&csum_preamble); | |
26711 | + memcpy(skb->data, &csum_preamble, 4); | |
26712 | + } | |
26713 | + } | |
26714 | + | |
26715 | + skb_push(skb, 4); | |
26716 | + tx_cmd_b = (u32)(skb->len - 4); | |
26717 | + if (csum) | |
26718 | + tx_cmd_b |= TX_CMD_B_CSUM_ENABLE; | |
26719 | + cpu_to_le32s(&tx_cmd_b); | |
26720 | + memcpy(skb->data, &tx_cmd_b, 4); | |
26721 | + | |
26722 | + skb_push(skb, 4); | |
26723 | + tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ | | |
26724 | + TX_CMD_A_LAST_SEG_; | |
26725 | + cpu_to_le32s(&tx_cmd_a); | |
26726 | + memcpy(skb->data, &tx_cmd_a, 4); | |
26727 | + | |
26728 | + return skb; | |
26729 | +} | |
26730 | + | |
26731 | +static int smsc95xx_manage_power(struct usbnet *dev, int on) | |
26732 | +{ | |
26733 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
26734 | + | |
26735 | + dev->intf->needs_remote_wakeup = on; | |
26736 | + | |
26737 | + if (pdata->features & FEATURE_REMOTE_WAKEUP) | |
26738 | + return 0; | |
26739 | + | |
26740 | + /* this chip revision isn't capable of remote wakeup */ | |
26741 | + netdev_info(dev->net, "hardware isn't capable of remote wakeup\n"); | |
26742 | + | |
26743 | + if (on) | |
26744 | + usb_autopm_get_interface_no_resume(dev->intf); | |
26745 | + else | |
26746 | + usb_autopm_put_interface(dev->intf); | |
26747 | + | |
26748 | + return 0; | |
26749 | +} | |
26750 | + | |
26751 | +static const struct driver_info smsc95xx_info = { | |
26752 | + .description = "smsc95xx USB 2.0 Ethernet", | |
26753 | + .bind = smsc95xx_bind, | |
26754 | + .unbind = smsc95xx_unbind, | |
26755 | + .link_reset = smsc95xx_link_reset, | |
26756 | + .reset = smsc95xx_reset, | |
26757 | + .rx_fixup = smsc95xx_rx_fixup, | |
26758 | + .tx_fixup = smsc95xx_tx_fixup, | |
26759 | + .status = smsc95xx_status, | |
26760 | + .manage_power = smsc95xx_manage_power, | |
26761 | + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, | |
26762 | +}; | |
26763 | + | |
26764 | +static const struct usb_device_id products[] = { | |
26765 | + { | |
26766 | + /* SMSC9500 USB Ethernet Device */ | |
26767 | + USB_DEVICE(0x0424, 0x9500), | |
26768 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26769 | + }, | |
26770 | + { | |
26771 | + /* SMSC9505 USB Ethernet Device */ | |
26772 | + USB_DEVICE(0x0424, 0x9505), | |
26773 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26774 | + }, | |
26775 | + { | |
26776 | + /* SMSC9500A USB Ethernet Device */ | |
26777 | + USB_DEVICE(0x0424, 0x9E00), | |
26778 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26779 | + }, | |
26780 | + { | |
26781 | + /* SMSC9505A USB Ethernet Device */ | |
26782 | + USB_DEVICE(0x0424, 0x9E01), | |
26783 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26784 | + }, | |
26785 | + { | |
26786 | + /* SMSC9512/9514 USB Hub & Ethernet Device */ | |
26787 | + USB_DEVICE(0x0424, 0xec00), | |
26788 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26789 | + }, | |
26790 | + { | |
26791 | + /* SMSC9500 USB Ethernet Device (SAL10) */ | |
26792 | + USB_DEVICE(0x0424, 0x9900), | |
26793 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26794 | + }, | |
26795 | + { | |
26796 | + /* SMSC9505 USB Ethernet Device (SAL10) */ | |
26797 | + USB_DEVICE(0x0424, 0x9901), | |
26798 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26799 | + }, | |
26800 | + { | |
26801 | + /* SMSC9500A USB Ethernet Device (SAL10) */ | |
26802 | + USB_DEVICE(0x0424, 0x9902), | |
26803 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26804 | + }, | |
26805 | + { | |
26806 | + /* SMSC9505A USB Ethernet Device (SAL10) */ | |
26807 | + USB_DEVICE(0x0424, 0x9903), | |
26808 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26809 | + }, | |
26810 | + { | |
26811 | + /* SMSC9512/9514 USB Hub & Ethernet Device (SAL10) */ | |
26812 | + USB_DEVICE(0x0424, 0x9904), | |
26813 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26814 | + }, | |
26815 | + { | |
26816 | + /* SMSC9500A USB Ethernet Device (HAL) */ | |
26817 | + USB_DEVICE(0x0424, 0x9905), | |
26818 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26819 | + }, | |
26820 | + { | |
26821 | + /* SMSC9505A USB Ethernet Device (HAL) */ | |
26822 | + USB_DEVICE(0x0424, 0x9906), | |
26823 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26824 | + }, | |
26825 | + { | |
26826 | + /* SMSC9500 USB Ethernet Device (Alternate ID) */ | |
26827 | + USB_DEVICE(0x0424, 0x9907), | |
26828 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26829 | + }, | |
26830 | + { | |
26831 | + /* SMSC9500A USB Ethernet Device (Alternate ID) */ | |
26832 | + USB_DEVICE(0x0424, 0x9908), | |
26833 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26834 | + }, | |
26835 | + { | |
26836 | + /* SMSC9512/9514 USB Hub & Ethernet Device (Alternate ID) */ | |
26837 | + USB_DEVICE(0x0424, 0x9909), | |
26838 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26839 | + }, | |
26840 | + { | |
26841 | + /* SMSC LAN9530 USB Ethernet Device */ | |
26842 | + USB_DEVICE(0x0424, 0x9530), | |
26843 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26844 | + }, | |
26845 | + { | |
26846 | + /* SMSC LAN9730 USB Ethernet Device */ | |
26847 | + USB_DEVICE(0x0424, 0x9730), | |
26848 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26849 | + }, | |
26850 | + { | |
26851 | + /* SMSC LAN89530 USB Ethernet Device */ | |
26852 | + USB_DEVICE(0x0424, 0x9E08), | |
26853 | + .driver_info = (unsigned long) &smsc95xx_info, | |
26854 | + }, | |
26855 | + { }, /* END */ | |
26856 | +}; | |
26857 | +MODULE_DEVICE_TABLE(usb, products); | |
26858 | + | |
26859 | +static struct usb_driver smsc95xx_driver = { | |
26860 | + .name = "smsc95xx", | |
26861 | + .id_table = products, | |
26862 | + .probe = usbnet_probe, | |
26863 | + .suspend = smsc95xx_suspend, | |
26864 | + .resume = smsc95xx_resume, | |
26865 | + .reset_resume = smsc95xx_reset_resume, | |
26866 | + .disconnect = usbnet_disconnect, | |
26867 | + .disable_hub_initiated_lpm = 1, | |
26868 | + .supports_autosuspend = 1, | |
26869 | +}; | |
26870 | + | |
26871 | +module_usb_driver(smsc95xx_driver); | |
26872 | + | |
26873 | +MODULE_AUTHOR("Nancy Lin"); | |
26874 | +MODULE_AUTHOR("Steve Glendinning <steve.glendinning@shawell.net>"); | |
26875 | +MODULE_DESCRIPTION("SMSC95XX USB 2.0 Ethernet Devices"); | |
26876 | +MODULE_LICENSE("GPL"); | |
26877 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/smsc95xx.h backports-3.18.1-1/drivers/net/usb/smsc95xx.h | |
26878 | --- backports-3.18.1-1.org/drivers/net/usb/smsc95xx.h 1970-01-01 01:00:00.000000000 +0100 | |
26879 | +++ backports-3.18.1-1/drivers/net/usb/smsc95xx.h 2014-12-16 18:39:45.000000000 +0100 | |
26880 | @@ -0,0 +1,290 @@ | |
26881 | + /*************************************************************************** | |
26882 | + * | |
26883 | + * Copyright (C) 2007-2008 SMSC | |
26884 | + * | |
26885 | + * This program is free software; you can redistribute it and/or | |
26886 | + * modify it under the terms of the GNU General Public License | |
26887 | + * as published by the Free Software Foundation; either version 2 | |
26888 | + * of the License, or (at your option) any later version. | |
26889 | + * | |
26890 | + * This program is distributed in the hope that it will be useful, | |
26891 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26892 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26893 | + * GNU General Public License for more details. | |
26894 | + * | |
26895 | + * You should have received a copy of the GNU General Public License | |
26896 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
26897 | + * | |
26898 | + *****************************************************************************/ | |
26899 | + | |
26900 | +#ifndef _SMSC95XX_H | |
26901 | +#define _SMSC95XX_H | |
26902 | + | |
26903 | +/* Tx command words */ | |
26904 | +#define TX_CMD_A_DATA_OFFSET_ (0x001F0000) | |
26905 | +#define TX_CMD_A_FIRST_SEG_ (0x00002000) | |
26906 | +#define TX_CMD_A_LAST_SEG_ (0x00001000) | |
26907 | +#define TX_CMD_A_BUF_SIZE_ (0x000007FF) | |
26908 | + | |
26909 | +#define TX_CMD_B_CSUM_ENABLE (0x00004000) | |
26910 | +#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000) | |
26911 | +#define TX_CMD_B_DISABLE_PADDING_ (0x00001000) | |
26912 | +#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF) | |
26913 | + | |
26914 | +/* Rx status word */ | |
26915 | +#define RX_STS_FF_ (0x40000000) /* Filter Fail */ | |
26916 | +#define RX_STS_FL_ (0x3FFF0000) /* Frame Length */ | |
26917 | +#define RX_STS_ES_ (0x00008000) /* Error Summary */ | |
26918 | +#define RX_STS_BF_ (0x00002000) /* Broadcast Frame */ | |
26919 | +#define RX_STS_LE_ (0x00001000) /* Length Error */ | |
26920 | +#define RX_STS_RF_ (0x00000800) /* Runt Frame */ | |
26921 | +#define RX_STS_MF_ (0x00000400) /* Multicast Frame */ | |
26922 | +#define RX_STS_TL_ (0x00000080) /* Frame too long */ | |
26923 | +#define RX_STS_CS_ (0x00000040) /* Collision Seen */ | |
26924 | +#define RX_STS_FT_ (0x00000020) /* Frame Type */ | |
26925 | +#define RX_STS_RW_ (0x00000010) /* Receive Watchdog */ | |
26926 | +#define RX_STS_ME_ (0x00000008) /* Mii Error */ | |
26927 | +#define RX_STS_DB_ (0x00000004) /* Dribbling */ | |
26928 | +#define RX_STS_CRC_ (0x00000002) /* CRC Error */ | |
26929 | + | |
26930 | +/* SCSRs */ | |
26931 | +#define ID_REV (0x00) | |
26932 | +#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000) | |
26933 | +#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) | |
26934 | +#define ID_REV_CHIP_ID_9500_ (0x9500) | |
26935 | +#define ID_REV_CHIP_ID_9500A_ (0x9E00) | |
26936 | +#define ID_REV_CHIP_ID_9512_ (0xEC00) | |
26937 | +#define ID_REV_CHIP_ID_9530_ (0x9530) | |
26938 | +#define ID_REV_CHIP_ID_89530_ (0x9E08) | |
26939 | +#define ID_REV_CHIP_ID_9730_ (0x9730) | |
26940 | + | |
26941 | +#define INT_STS (0x08) | |
26942 | +#define INT_STS_TX_STOP_ (0x00020000) | |
26943 | +#define INT_STS_RX_STOP_ (0x00010000) | |
26944 | +#define INT_STS_PHY_INT_ (0x00008000) | |
26945 | +#define INT_STS_TXE_ (0x00004000) | |
26946 | +#define INT_STS_TDFU_ (0x00002000) | |
26947 | +#define INT_STS_TDFO_ (0x00001000) | |
26948 | +#define INT_STS_RXDF_ (0x00000800) | |
26949 | +#define INT_STS_GPIOS_ (0x000007FF) | |
26950 | +#define INT_STS_CLEAR_ALL_ (0xFFFFFFFF) | |
26951 | + | |
26952 | +#define RX_CFG (0x0C) | |
26953 | +#define RX_FIFO_FLUSH_ (0x00000001) | |
26954 | + | |
26955 | +#define TX_CFG (0x10) | |
26956 | +#define TX_CFG_ON_ (0x00000004) | |
26957 | +#define TX_CFG_STOP_ (0x00000002) | |
26958 | +#define TX_CFG_FIFO_FLUSH_ (0x00000001) | |
26959 | + | |
26960 | +#define HW_CFG (0x14) | |
26961 | +#define HW_CFG_BIR_ (0x00001000) | |
26962 | +#define HW_CFG_LEDB_ (0x00000800) | |
26963 | +#define HW_CFG_RXDOFF_ (0x00000600) | |
26964 | +#define HW_CFG_DRP_ (0x00000040) | |
26965 | +#define HW_CFG_MEF_ (0x00000020) | |
26966 | +#define HW_CFG_LRST_ (0x00000008) | |
26967 | +#define HW_CFG_PSEL_ (0x00000004) | |
26968 | +#define HW_CFG_BCE_ (0x00000002) | |
26969 | +#define HW_CFG_SRST_ (0x00000001) | |
26970 | + | |
26971 | +#define RX_FIFO_INF (0x18) | |
26972 | + | |
26973 | +#define PM_CTRL (0x20) | |
26974 | +#define PM_CTL_RES_CLR_WKP_STS (0x00000200) | |
26975 | +#define PM_CTL_DEV_RDY_ (0x00000080) | |
26976 | +#define PM_CTL_SUS_MODE_ (0x00000060) | |
26977 | +#define PM_CTL_SUS_MODE_0 (0x00000000) | |
26978 | +#define PM_CTL_SUS_MODE_1 (0x00000020) | |
26979 | +#define PM_CTL_SUS_MODE_2 (0x00000040) | |
26980 | +#define PM_CTL_SUS_MODE_3 (0x00000060) | |
26981 | +#define PM_CTL_PHY_RST_ (0x00000010) | |
26982 | +#define PM_CTL_WOL_EN_ (0x00000008) | |
26983 | +#define PM_CTL_ED_EN_ (0x00000004) | |
26984 | +#define PM_CTL_WUPS_ (0x00000003) | |
26985 | +#define PM_CTL_WUPS_NO_ (0x00000000) | |
26986 | +#define PM_CTL_WUPS_ED_ (0x00000001) | |
26987 | +#define PM_CTL_WUPS_WOL_ (0x00000002) | |
26988 | +#define PM_CTL_WUPS_MULTI_ (0x00000003) | |
26989 | + | |
26990 | +#define LED_GPIO_CFG (0x24) | |
26991 | +#define LED_GPIO_CFG_SPD_LED (0x01000000) | |
26992 | +#define LED_GPIO_CFG_LNK_LED (0x00100000) | |
26993 | +#define LED_GPIO_CFG_FDX_LED (0x00010000) | |
26994 | + | |
26995 | +#define GPIO_CFG (0x28) | |
26996 | + | |
26997 | +#define AFC_CFG (0x2C) | |
26998 | + | |
26999 | +/* Hi watermark = 15.5Kb (~10 mtu pkts) */ | |
27000 | +/* low watermark = 3k (~2 mtu pkts) */ | |
27001 | +/* backpressure duration = ~ 350us */ | |
27002 | +/* Apply FC on any frame. */ | |
27003 | +#define AFC_CFG_DEFAULT (0x00F830A1) | |
27004 | + | |
27005 | +#define E2P_CMD (0x30) | |
27006 | +#define E2P_CMD_BUSY_ (0x80000000) | |
27007 | +#define E2P_CMD_MASK_ (0x70000000) | |
27008 | +#define E2P_CMD_READ_ (0x00000000) | |
27009 | +#define E2P_CMD_EWDS_ (0x10000000) | |
27010 | +#define E2P_CMD_EWEN_ (0x20000000) | |
27011 | +#define E2P_CMD_WRITE_ (0x30000000) | |
27012 | +#define E2P_CMD_WRAL_ (0x40000000) | |
27013 | +#define E2P_CMD_ERASE_ (0x50000000) | |
27014 | +#define E2P_CMD_ERAL_ (0x60000000) | |
27015 | +#define E2P_CMD_RELOAD_ (0x70000000) | |
27016 | +#define E2P_CMD_TIMEOUT_ (0x00000400) | |
27017 | +#define E2P_CMD_LOADED_ (0x00000200) | |
27018 | +#define E2P_CMD_ADDR_ (0x000001FF) | |
27019 | + | |
27020 | +#define MAX_EEPROM_SIZE (512) | |
27021 | + | |
27022 | +#define E2P_DATA (0x34) | |
27023 | +#define E2P_DATA_MASK_ (0x000000FF) | |
27024 | + | |
27025 | +#define BURST_CAP (0x38) | |
27026 | + | |
27027 | +#define GPIO_WAKE (0x64) | |
27028 | + | |
27029 | +#define INT_EP_CTL (0x68) | |
27030 | +#define INT_EP_CTL_INTEP_ (0x80000000) | |
27031 | +#define INT_EP_CTL_MACRTO_ (0x00080000) | |
27032 | +#define INT_EP_CTL_TX_STOP_ (0x00020000) | |
27033 | +#define INT_EP_CTL_RX_STOP_ (0x00010000) | |
27034 | +#define INT_EP_CTL_PHY_INT_ (0x00008000) | |
27035 | +#define INT_EP_CTL_TXE_ (0x00004000) | |
27036 | +#define INT_EP_CTL_TDFU_ (0x00002000) | |
27037 | +#define INT_EP_CTL_TDFO_ (0x00001000) | |
27038 | +#define INT_EP_CTL_RXDF_ (0x00000800) | |
27039 | +#define INT_EP_CTL_GPIOS_ (0x000007FF) | |
27040 | + | |
27041 | +#define BULK_IN_DLY (0x6C) | |
27042 | + | |
27043 | +/* MAC CSRs */ | |
27044 | +#define MAC_CR (0x100) | |
27045 | +#define MAC_CR_RXALL_ (0x80000000) | |
27046 | +#define MAC_CR_RCVOWN_ (0x00800000) | |
27047 | +#define MAC_CR_LOOPBK_ (0x00200000) | |
27048 | +#define MAC_CR_FDPX_ (0x00100000) | |
27049 | +#define MAC_CR_MCPAS_ (0x00080000) | |
27050 | +#define MAC_CR_PRMS_ (0x00040000) | |
27051 | +#define MAC_CR_INVFILT_ (0x00020000) | |
27052 | +#define MAC_CR_PASSBAD_ (0x00010000) | |
27053 | +#define MAC_CR_HFILT_ (0x00008000) | |
27054 | +#define MAC_CR_HPFILT_ (0x00002000) | |
27055 | +#define MAC_CR_LCOLL_ (0x00001000) | |
27056 | +#define MAC_CR_BCAST_ (0x00000800) | |
27057 | +#define MAC_CR_DISRTY_ (0x00000400) | |
27058 | +#define MAC_CR_PADSTR_ (0x00000100) | |
27059 | +#define MAC_CR_BOLMT_MASK (0x000000C0) | |
27060 | +#define MAC_CR_DFCHK_ (0x00000020) | |
27061 | +#define MAC_CR_TXEN_ (0x00000008) | |
27062 | +#define MAC_CR_RXEN_ (0x00000004) | |
27063 | + | |
27064 | +#define ADDRH (0x104) | |
27065 | + | |
27066 | +#define ADDRL (0x108) | |
27067 | + | |
27068 | +#define HASHH (0x10C) | |
27069 | + | |
27070 | +#define HASHL (0x110) | |
27071 | + | |
27072 | +#define MII_ADDR (0x114) | |
27073 | +#define MII_WRITE_ (0x02) | |
27074 | +#define MII_BUSY_ (0x01) | |
27075 | +#define MII_READ_ (0x00) /* ~of MII Write bit */ | |
27076 | + | |
27077 | +#define MII_DATA (0x118) | |
27078 | + | |
27079 | +#define FLOW (0x11C) | |
27080 | +#define FLOW_FCPT_ (0xFFFF0000) | |
27081 | +#define FLOW_FCPASS_ (0x00000004) | |
27082 | +#define FLOW_FCEN_ (0x00000002) | |
27083 | +#define FLOW_FCBSY_ (0x00000001) | |
27084 | + | |
27085 | +#define VLAN1 (0x120) | |
27086 | + | |
27087 | +#define VLAN2 (0x124) | |
27088 | + | |
27089 | +#define WUFF (0x128) | |
27090 | +#define LAN9500_WUFF_NUM (4) | |
27091 | +#define LAN9500A_WUFF_NUM (8) | |
27092 | + | |
27093 | +#define WUCSR (0x12C) | |
27094 | +#define WUCSR_WFF_PTR_RST_ (0x80000000) | |
27095 | +#define WUCSR_GUE_ (0x00000200) | |
27096 | +#define WUCSR_WUFR_ (0x00000040) | |
27097 | +#define WUCSR_MPR_ (0x00000020) | |
27098 | +#define WUCSR_WAKE_EN_ (0x00000004) | |
27099 | +#define WUCSR_MPEN_ (0x00000002) | |
27100 | + | |
27101 | +#define COE_CR (0x130) | |
27102 | +#define Tx_COE_EN_ (0x00010000) | |
27103 | +#define Rx_COE_MODE_ (0x00000002) | |
27104 | +#define Rx_COE_EN_ (0x00000001) | |
27105 | + | |
27106 | +/* Vendor-specific PHY Definitions */ | |
27107 | + | |
27108 | +/* EDPD NLP / crossover time configuration (LAN9500A only) */ | |
27109 | +#define PHY_EDPD_CONFIG (16) | |
27110 | +#define PHY_EDPD_CONFIG_TX_NLP_EN_ ((u16)0x8000) | |
27111 | +#define PHY_EDPD_CONFIG_TX_NLP_1000_ ((u16)0x0000) | |
27112 | +#define PHY_EDPD_CONFIG_TX_NLP_768_ ((u16)0x2000) | |
27113 | +#define PHY_EDPD_CONFIG_TX_NLP_512_ ((u16)0x4000) | |
27114 | +#define PHY_EDPD_CONFIG_TX_NLP_256_ ((u16)0x6000) | |
27115 | +#define PHY_EDPD_CONFIG_RX_1_NLP_ ((u16)0x1000) | |
27116 | +#define PHY_EDPD_CONFIG_RX_NLP_64_ ((u16)0x0000) | |
27117 | +#define PHY_EDPD_CONFIG_RX_NLP_256_ ((u16)0x0400) | |
27118 | +#define PHY_EDPD_CONFIG_RX_NLP_512_ ((u16)0x0800) | |
27119 | +#define PHY_EDPD_CONFIG_RX_NLP_1000_ ((u16)0x0C00) | |
27120 | +#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ ((u16)0x0001) | |
27121 | +#define PHY_EDPD_CONFIG_DEFAULT (PHY_EDPD_CONFIG_TX_NLP_EN_ | \ | |
27122 | + PHY_EDPD_CONFIG_TX_NLP_768_ | \ | |
27123 | + PHY_EDPD_CONFIG_RX_1_NLP_) | |
27124 | + | |
27125 | +/* Mode Control/Status Register */ | |
27126 | +#define PHY_MODE_CTRL_STS (17) | |
27127 | +#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) | |
27128 | +#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002) | |
27129 | + | |
27130 | +#define SPECIAL_CTRL_STS (27) | |
27131 | +#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((u16)0x8000) | |
27132 | +#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((u16)0x4000) | |
27133 | +#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((u16)0x2000) | |
27134 | + | |
27135 | +#define PHY_INT_SRC (29) | |
27136 | +#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080) | |
27137 | +#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040) | |
27138 | +#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020) | |
27139 | +#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010) | |
27140 | + | |
27141 | +#define PHY_INT_MASK (30) | |
27142 | +#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080) | |
27143 | +#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) | |
27144 | +#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020) | |
27145 | +#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) | |
27146 | +#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \ | |
27147 | + PHY_INT_MASK_LINK_DOWN_) | |
27148 | + | |
27149 | +#define PHY_SPECIAL (31) | |
27150 | +#define PHY_SPECIAL_SPD_ ((u16)0x001C) | |
27151 | +#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004) | |
27152 | +#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014) | |
27153 | +#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008) | |
27154 | +#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018) | |
27155 | + | |
27156 | +/* USB Vendor Requests */ | |
27157 | +#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 | |
27158 | +#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 | |
27159 | +#define USB_VENDOR_REQUEST_GET_STATS 0xA2 | |
27160 | + | |
27161 | +/* Interrupt Endpoint status word bitfields */ | |
27162 | +#define INT_ENP_TX_STOP_ ((u32)BIT(17)) | |
27163 | +#define INT_ENP_RX_STOP_ ((u32)BIT(16)) | |
27164 | +#define INT_ENP_PHY_INT_ ((u32)BIT(15)) | |
27165 | +#define INT_ENP_TXE_ ((u32)BIT(14)) | |
27166 | +#define INT_ENP_TDFU_ ((u32)BIT(13)) | |
27167 | +#define INT_ENP_TDFO_ ((u32)BIT(12)) | |
27168 | +#define INT_ENP_RXDF_ ((u32)BIT(11)) | |
27169 | + | |
27170 | +#endif /* _SMSC95XX_H */ | |
27171 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/sr9700.c backports-3.18.1-1/drivers/net/usb/sr9700.c | |
27172 | --- backports-3.18.1-1.org/drivers/net/usb/sr9700.c 1970-01-01 01:00:00.000000000 +0100 | |
27173 | +++ backports-3.18.1-1/drivers/net/usb/sr9700.c 2014-12-16 18:39:45.000000000 +0100 | |
27174 | @@ -0,0 +1,559 @@ | |
27175 | +/* | |
27176 | + * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices | |
27177 | + * | |
27178 | + * Author : Liu Junliang <liujunliang_ljl@163.com> | |
27179 | + * | |
27180 | + * Based on dm9601.c | |
27181 | + * | |
27182 | + * This file is licensed under the terms of the GNU General Public License | |
27183 | + * version 2. This program is licensed "as is" without any warranty of any | |
27184 | + * kind, whether express or implied. | |
27185 | + */ | |
27186 | + | |
27187 | +#include <linux/module.h> | |
27188 | +#include <linux/sched.h> | |
27189 | +#include <linux/stddef.h> | |
27190 | +#include <linux/netdevice.h> | |
27191 | +#include <linux/etherdevice.h> | |
27192 | +#include <linux/ethtool.h> | |
27193 | +#include <linux/mii.h> | |
27194 | +#include <linux/usb.h> | |
27195 | +#include <linux/crc32.h> | |
27196 | +#include <linux/usb/usbnet.h> | |
27197 | + | |
27198 | +#include "sr9700.h" | |
27199 | + | |
27200 | +static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data) | |
27201 | +{ | |
27202 | + int err; | |
27203 | + | |
27204 | + err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data, | |
27205 | + length); | |
27206 | + if ((err != length) && (err >= 0)) | |
27207 | + err = -EINVAL; | |
27208 | + return err; | |
27209 | +} | |
27210 | + | |
27211 | +static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data) | |
27212 | +{ | |
27213 | + int err; | |
27214 | + | |
27215 | + err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data, | |
27216 | + length); | |
27217 | + if ((err >= 0) && (err < length)) | |
27218 | + err = -EINVAL; | |
27219 | + return err; | |
27220 | +} | |
27221 | + | |
27222 | +static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) | |
27223 | +{ | |
27224 | + return sr_read(dev, reg, 1, value); | |
27225 | +} | |
27226 | + | |
27227 | +static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) | |
27228 | +{ | |
27229 | + return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, | |
27230 | + value, reg, NULL, 0); | |
27231 | +} | |
27232 | + | |
27233 | +static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) | |
27234 | +{ | |
27235 | + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, | |
27236 | + 0, reg, data, length); | |
27237 | +} | |
27238 | + | |
27239 | +static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) | |
27240 | +{ | |
27241 | + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, | |
27242 | + value, reg, NULL, 0); | |
27243 | +} | |
27244 | + | |
27245 | +static int wait_phy_eeprom_ready(struct usbnet *dev, int phy) | |
27246 | +{ | |
27247 | + int i; | |
27248 | + | |
27249 | + for (i = 0; i < SR_SHARE_TIMEOUT; i++) { | |
27250 | + u8 tmp = 0; | |
27251 | + int ret; | |
27252 | + | |
27253 | + udelay(1); | |
27254 | + ret = sr_read_reg(dev, EPCR, &tmp); | |
27255 | + if (ret < 0) | |
27256 | + return ret; | |
27257 | + | |
27258 | + /* ready */ | |
27259 | + if (!(tmp & EPCR_ERRE)) | |
27260 | + return 0; | |
27261 | + } | |
27262 | + | |
27263 | + netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom"); | |
27264 | + | |
27265 | + return -EIO; | |
27266 | +} | |
27267 | + | |
27268 | +static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, | |
27269 | + __le16 *value) | |
27270 | +{ | |
27271 | + int ret; | |
27272 | + | |
27273 | + mutex_lock(&dev->phy_mutex); | |
27274 | + | |
27275 | + sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); | |
27276 | + sr_write_reg(dev, EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR); | |
27277 | + | |
27278 | + ret = wait_phy_eeprom_ready(dev, phy); | |
27279 | + if (ret < 0) | |
27280 | + goto out_unlock; | |
27281 | + | |
27282 | + sr_write_reg(dev, EPCR, 0x0); | |
27283 | + ret = sr_read(dev, EPDR, 2, value); | |
27284 | + | |
27285 | + netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", | |
27286 | + phy, reg, *value, ret); | |
27287 | + | |
27288 | +out_unlock: | |
27289 | + mutex_unlock(&dev->phy_mutex); | |
27290 | + return ret; | |
27291 | +} | |
27292 | + | |
27293 | +static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, | |
27294 | + __le16 value) | |
27295 | +{ | |
27296 | + int ret; | |
27297 | + | |
27298 | + mutex_lock(&dev->phy_mutex); | |
27299 | + | |
27300 | + ret = sr_write(dev, EPDR, 2, &value); | |
27301 | + if (ret < 0) | |
27302 | + goto out_unlock; | |
27303 | + | |
27304 | + sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); | |
27305 | + sr_write_reg(dev, EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) : | |
27306 | + (EPCR_WEP | EPCR_ERPRW)); | |
27307 | + | |
27308 | + ret = wait_phy_eeprom_ready(dev, phy); | |
27309 | + if (ret < 0) | |
27310 | + goto out_unlock; | |
27311 | + | |
27312 | + sr_write_reg(dev, EPCR, 0x0); | |
27313 | + | |
27314 | +out_unlock: | |
27315 | + mutex_unlock(&dev->phy_mutex); | |
27316 | + return ret; | |
27317 | +} | |
27318 | + | |
27319 | +static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) | |
27320 | +{ | |
27321 | + return sr_share_read_word(dev, 0, offset, value); | |
27322 | +} | |
27323 | + | |
27324 | +static int sr9700_get_eeprom_len(struct net_device *netdev) | |
27325 | +{ | |
27326 | + return SR_EEPROM_LEN; | |
27327 | +} | |
27328 | + | |
27329 | +static int sr9700_get_eeprom(struct net_device *netdev, | |
27330 | + struct ethtool_eeprom *eeprom, u8 *data) | |
27331 | +{ | |
27332 | + struct usbnet *dev = netdev_priv(netdev); | |
27333 | + __le16 *buf = (__le16 *)data; | |
27334 | + int ret = 0; | |
27335 | + int i; | |
27336 | + | |
27337 | + /* access is 16bit */ | |
27338 | + if ((eeprom->offset & 0x01) || (eeprom->len & 0x01)) | |
27339 | + return -EINVAL; | |
27340 | + | |
27341 | + for (i = 0; i < eeprom->len / 2; i++) { | |
27342 | + ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i); | |
27343 | + if (ret < 0) | |
27344 | + break; | |
27345 | + } | |
27346 | + | |
27347 | + return ret; | |
27348 | +} | |
27349 | + | |
27350 | +static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) | |
27351 | +{ | |
27352 | + struct usbnet *dev = netdev_priv(netdev); | |
27353 | + __le16 res; | |
27354 | + int rc = 0; | |
27355 | + | |
27356 | + if (phy_id) { | |
27357 | + netdev_dbg(netdev, "Only internal phy supported\n"); | |
27358 | + return 0; | |
27359 | + } | |
27360 | + | |
27361 | + /* Access NSR_LINKST bit for link status instead of MII_BMSR */ | |
27362 | + if (loc == MII_BMSR) { | |
27363 | + u8 value; | |
27364 | + | |
27365 | + sr_read_reg(dev, NSR, &value); | |
27366 | + if (value & NSR_LINKST) | |
27367 | + rc = 1; | |
27368 | + } | |
27369 | + sr_share_read_word(dev, 1, loc, &res); | |
27370 | + if (rc == 1) | |
27371 | + res = le16_to_cpu(res) | BMSR_LSTATUS; | |
27372 | + else | |
27373 | + res = le16_to_cpu(res) & ~BMSR_LSTATUS; | |
27374 | + | |
27375 | + netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", | |
27376 | + phy_id, loc, res); | |
27377 | + | |
27378 | + return res; | |
27379 | +} | |
27380 | + | |
27381 | +static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, | |
27382 | + int val) | |
27383 | +{ | |
27384 | + struct usbnet *dev = netdev_priv(netdev); | |
27385 | + __le16 res = cpu_to_le16(val); | |
27386 | + | |
27387 | + if (phy_id) { | |
27388 | + netdev_dbg(netdev, "Only internal phy supported\n"); | |
27389 | + return; | |
27390 | + } | |
27391 | + | |
27392 | + netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", | |
27393 | + phy_id, loc, val); | |
27394 | + | |
27395 | + sr_share_write_word(dev, 1, loc, res); | |
27396 | +} | |
27397 | + | |
27398 | +static u32 sr9700_get_link(struct net_device *netdev) | |
27399 | +{ | |
27400 | + struct usbnet *dev = netdev_priv(netdev); | |
27401 | + u8 value = 0; | |
27402 | + int rc = 0; | |
27403 | + | |
27404 | + /* Get the Link Status directly */ | |
27405 | + sr_read_reg(dev, NSR, &value); | |
27406 | + if (value & NSR_LINKST) | |
27407 | + rc = 1; | |
27408 | + | |
27409 | + return rc; | |
27410 | +} | |
27411 | + | |
27412 | +static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
27413 | +{ | |
27414 | + struct usbnet *dev = netdev_priv(netdev); | |
27415 | + | |
27416 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
27417 | +} | |
27418 | + | |
27419 | +static const struct ethtool_ops sr9700_ethtool_ops = { | |
27420 | + .get_drvinfo = usbnet_get_drvinfo, | |
27421 | + .get_link = sr9700_get_link, | |
27422 | + .get_msglevel = usbnet_get_msglevel, | |
27423 | + .set_msglevel = usbnet_set_msglevel, | |
27424 | + .get_eeprom_len = sr9700_get_eeprom_len, | |
27425 | + .get_eeprom = sr9700_get_eeprom, | |
27426 | + .get_settings = usbnet_get_settings, | |
27427 | + .set_settings = usbnet_set_settings, | |
27428 | + .nway_reset = usbnet_nway_reset, | |
27429 | +}; | |
27430 | + | |
27431 | +static void sr9700_set_multicast(struct net_device *netdev) | |
27432 | +{ | |
27433 | + struct usbnet *dev = netdev_priv(netdev); | |
27434 | + /* We use the 20 byte dev->data for our 8 byte filter buffer | |
27435 | + * to avoid allocating memory that is tricky to free later | |
27436 | + */ | |
27437 | + u8 *hashes = (u8 *)&dev->data; | |
27438 | + /* rx_ctl setting : enable, disable_long, disable_crc */ | |
27439 | + u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG; | |
27440 | + | |
27441 | + memset(hashes, 0x00, SR_MCAST_SIZE); | |
27442 | + /* broadcast address */ | |
27443 | + hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG; | |
27444 | + if (netdev->flags & IFF_PROMISC) { | |
27445 | + rx_ctl |= RCR_PRMSC; | |
27446 | + } else if (netdev->flags & IFF_ALLMULTI || | |
27447 | + netdev_mc_count(netdev) > SR_MCAST_MAX) { | |
27448 | + rx_ctl |= RCR_RUNT; | |
27449 | + } else if (!netdev_mc_empty(netdev)) { | |
27450 | + struct netdev_hw_addr *ha; | |
27451 | + | |
27452 | + netdev_for_each_mc_addr(ha, netdev) { | |
27453 | + u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
27454 | + hashes[crc >> 3] |= 1 << (crc & 0x7); | |
27455 | + } | |
27456 | + } | |
27457 | + | |
27458 | + sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes); | |
27459 | + sr_write_reg_async(dev, RCR, rx_ctl); | |
27460 | +} | |
27461 | + | |
27462 | +static int sr9700_set_mac_address(struct net_device *netdev, void *p) | |
27463 | +{ | |
27464 | + struct usbnet *dev = netdev_priv(netdev); | |
27465 | + struct sockaddr *addr = p; | |
27466 | + | |
27467 | + if (!is_valid_ether_addr(addr->sa_data)) { | |
27468 | + netdev_err(netdev, "not setting invalid mac address %pM\n", | |
27469 | + addr->sa_data); | |
27470 | + return -EINVAL; | |
27471 | + } | |
27472 | + | |
27473 | + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | |
27474 | + sr_write_async(dev, PAR, 6, netdev->dev_addr); | |
27475 | + | |
27476 | + return 0; | |
27477 | +} | |
27478 | + | |
27479 | +static const struct net_device_ops sr9700_netdev_ops = { | |
27480 | + .ndo_open = usbnet_open, | |
27481 | + .ndo_stop = usbnet_stop, | |
27482 | + .ndo_start_xmit = usbnet_start_xmit, | |
27483 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
27484 | + .ndo_change_mtu = usbnet_change_mtu, | |
27485 | + .ndo_validate_addr = eth_validate_addr, | |
27486 | + .ndo_do_ioctl = sr9700_ioctl, | |
27487 | + .ndo_set_rx_mode = sr9700_set_multicast, | |
27488 | + .ndo_set_mac_address = sr9700_set_mac_address, | |
27489 | +}; | |
27490 | + | |
27491 | +static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf) | |
27492 | +{ | |
27493 | + struct net_device *netdev; | |
27494 | + struct mii_if_info *mii; | |
27495 | + int ret; | |
27496 | + | |
27497 | + ret = usbnet_get_endpoints(dev, intf); | |
27498 | + if (ret) | |
27499 | + goto out; | |
27500 | + | |
27501 | + netdev = dev->net; | |
27502 | + | |
27503 | + netdev->netdev_ops = &sr9700_netdev_ops; | |
27504 | + netdev->ethtool_ops = &sr9700_ethtool_ops; | |
27505 | + netdev->hard_header_len += SR_TX_OVERHEAD; | |
27506 | + dev->hard_mtu = netdev->mtu + netdev->hard_header_len; | |
27507 | + /* bulkin buffer is preferably not less than 3K */ | |
27508 | + dev->rx_urb_size = 3072; | |
27509 | + | |
27510 | + mii = &dev->mii; | |
27511 | + mii->dev = netdev; | |
27512 | + mii->mdio_read = sr_mdio_read; | |
27513 | + mii->mdio_write = sr_mdio_write; | |
27514 | + mii->phy_id_mask = 0x1f; | |
27515 | + mii->reg_num_mask = 0x1f; | |
27516 | + | |
27517 | + sr_write_reg(dev, NCR, NCR_RST); | |
27518 | + udelay(20); | |
27519 | + | |
27520 | + /* read MAC | |
27521 | + * After Chip Power on, the Chip will reload the MAC from | |
27522 | + * EEPROM automatically to PAR. In case there is no EEPROM externally, | |
27523 | + * a default MAC address is stored in PAR for making chip work properly. | |
27524 | + */ | |
27525 | + if (sr_read(dev, PAR, ETH_ALEN, netdev->dev_addr) < 0) { | |
27526 | + netdev_err(netdev, "Error reading MAC address\n"); | |
27527 | + ret = -ENODEV; | |
27528 | + goto out; | |
27529 | + } | |
27530 | + | |
27531 | + /* power up and reset phy */ | |
27532 | + sr_write_reg(dev, PRR, PRR_PHY_RST); | |
27533 | + /* at least 10ms, here 20ms for safe */ | |
27534 | + mdelay(20); | |
27535 | + sr_write_reg(dev, PRR, 0); | |
27536 | + /* at least 1ms, here 2ms for reading right register */ | |
27537 | + udelay(2 * 1000); | |
27538 | + | |
27539 | + /* receive broadcast packets */ | |
27540 | + sr9700_set_multicast(netdev); | |
27541 | + | |
27542 | + sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET); | |
27543 | + sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL | | |
27544 | + ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); | |
27545 | + mii_nway_restart(mii); | |
27546 | + | |
27547 | +out: | |
27548 | + return ret; | |
27549 | +} | |
27550 | + | |
27551 | +static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
27552 | +{ | |
27553 | + struct sk_buff *sr_skb; | |
27554 | + int len; | |
27555 | + | |
27556 | + /* skb content (packets) format : | |
27557 | + * p0 p1 p2 ...... pm | |
27558 | + * / \ | |
27559 | + * / \ | |
27560 | + * / \ | |
27561 | + * / \ | |
27562 | + * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn | |
27563 | + * | |
27564 | + * p0 : packet 0 | |
27565 | + * p0b0 : packet 0 byte 0 | |
27566 | + * | |
27567 | + * b0: rx status | |
27568 | + * b1: packet length (incl crc) low | |
27569 | + * b2: packet length (incl crc) high | |
27570 | + * b3..n-4: packet data | |
27571 | + * bn-3..bn: ethernet packet crc | |
27572 | + */ | |
27573 | + if (unlikely(skb->len < SR_RX_OVERHEAD)) { | |
27574 | + netdev_err(dev->net, "unexpected tiny rx frame\n"); | |
27575 | + return 0; | |
27576 | + } | |
27577 | + | |
27578 | + /* one skb may contains multiple packets */ | |
27579 | + while (skb->len > SR_RX_OVERHEAD) { | |
27580 | + if (skb->data[0] != 0x40) | |
27581 | + return 0; | |
27582 | + | |
27583 | + /* ignore the CRC length */ | |
27584 | + len = (skb->data[1] | (skb->data[2] << 8)) - 4; | |
27585 | + | |
27586 | + if (len > ETH_FRAME_LEN) | |
27587 | + return 0; | |
27588 | + | |
27589 | + /* the last packet of current skb */ | |
27590 | + if (skb->len == (len + SR_RX_OVERHEAD)) { | |
27591 | + skb_pull(skb, 3); | |
27592 | + skb->len = len; | |
27593 | + skb_set_tail_pointer(skb, len); | |
27594 | + skb->truesize = len + sizeof(struct sk_buff); | |
27595 | + return 2; | |
27596 | + } | |
27597 | + | |
27598 | + /* skb_clone is used for address align */ | |
27599 | + sr_skb = skb_clone(skb, GFP_ATOMIC); | |
27600 | + if (!sr_skb) | |
27601 | + return 0; | |
27602 | + | |
27603 | + sr_skb->len = len; | |
27604 | + sr_skb->data = skb->data + 3; | |
27605 | + skb_set_tail_pointer(sr_skb, len); | |
27606 | + sr_skb->truesize = len + sizeof(struct sk_buff); | |
27607 | + usbnet_skb_return(dev, sr_skb); | |
27608 | + | |
27609 | + skb_pull(skb, len + SR_RX_OVERHEAD); | |
27610 | + }; | |
27611 | + | |
27612 | + return 0; | |
27613 | +} | |
27614 | + | |
27615 | +static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
27616 | + gfp_t flags) | |
27617 | +{ | |
27618 | + int len; | |
27619 | + | |
27620 | + /* SR9700 can only send out one ethernet packet at once. | |
27621 | + * | |
27622 | + * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn | |
27623 | + * | |
27624 | + * b0: rx status | |
27625 | + * b1: packet length (incl crc) low | |
27626 | + * b2: packet length (incl crc) high | |
27627 | + * b3..n-4: packet data | |
27628 | + * bn-3..bn: ethernet packet crc | |
27629 | + */ | |
27630 | + | |
27631 | + len = skb->len; | |
27632 | + | |
27633 | + if (skb_headroom(skb) < SR_TX_OVERHEAD) { | |
27634 | + struct sk_buff *skb2; | |
27635 | + | |
27636 | + skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags); | |
27637 | + dev_kfree_skb_any(skb); | |
27638 | + skb = skb2; | |
27639 | + if (!skb) | |
27640 | + return NULL; | |
27641 | + } | |
27642 | + | |
27643 | + __skb_push(skb, SR_TX_OVERHEAD); | |
27644 | + | |
27645 | + /* usbnet adds padding if length is a multiple of packet size | |
27646 | + * if so, adjust length value in header | |
27647 | + */ | |
27648 | + if ((skb->len % dev->maxpacket) == 0) | |
27649 | + len++; | |
27650 | + | |
27651 | + skb->data[0] = len; | |
27652 | + skb->data[1] = len >> 8; | |
27653 | + | |
27654 | + return skb; | |
27655 | +} | |
27656 | + | |
27657 | +static void sr9700_status(struct usbnet *dev, struct urb *urb) | |
27658 | +{ | |
27659 | + int link; | |
27660 | + u8 *buf; | |
27661 | + | |
27662 | + /* format: | |
27663 | + b0: net status | |
27664 | + b1: tx status 1 | |
27665 | + b2: tx status 2 | |
27666 | + b3: rx status | |
27667 | + b4: rx overflow | |
27668 | + b5: rx count | |
27669 | + b6: tx count | |
27670 | + b7: gpr | |
27671 | + */ | |
27672 | + | |
27673 | + if (urb->actual_length < 8) | |
27674 | + return; | |
27675 | + | |
27676 | + buf = urb->transfer_buffer; | |
27677 | + | |
27678 | + link = !!(buf[0] & 0x40); | |
27679 | + if (netif_carrier_ok(dev->net) != link) { | |
27680 | + usbnet_link_change(dev, link, 1); | |
27681 | + netdev_dbg(dev->net, "Link Status is: %d\n", link); | |
27682 | + } | |
27683 | +} | |
27684 | + | |
27685 | +static int sr9700_link_reset(struct usbnet *dev) | |
27686 | +{ | |
27687 | + struct ethtool_cmd ecmd; | |
27688 | + | |
27689 | + mii_check_media(&dev->mii, 1, 1); | |
27690 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
27691 | + | |
27692 | + netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", | |
27693 | + ecmd.speed, ecmd.duplex); | |
27694 | + | |
27695 | + return 0; | |
27696 | +} | |
27697 | + | |
27698 | +static const struct driver_info sr9700_driver_info = { | |
27699 | + .description = "CoreChip SR9700 USB Ethernet", | |
27700 | + .flags = FLAG_ETHER, | |
27701 | + .bind = sr9700_bind, | |
27702 | + .rx_fixup = sr9700_rx_fixup, | |
27703 | + .tx_fixup = sr9700_tx_fixup, | |
27704 | + .status = sr9700_status, | |
27705 | + .link_reset = sr9700_link_reset, | |
27706 | + .reset = sr9700_link_reset, | |
27707 | +}; | |
27708 | + | |
27709 | +static const struct usb_device_id products[] = { | |
27710 | + { | |
27711 | + USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */ | |
27712 | + .driver_info = (unsigned long)&sr9700_driver_info, | |
27713 | + }, | |
27714 | + {}, /* END */ | |
27715 | +}; | |
27716 | + | |
27717 | +MODULE_DEVICE_TABLE(usb, products); | |
27718 | + | |
27719 | +static struct usb_driver sr9700_usb_driver = { | |
27720 | + .name = "sr9700", | |
27721 | + .id_table = products, | |
27722 | + .probe = usbnet_probe, | |
27723 | + .disconnect = usbnet_disconnect, | |
27724 | + .suspend = usbnet_suspend, | |
27725 | + .resume = usbnet_resume, | |
27726 | + .disable_hub_initiated_lpm = 1, | |
27727 | +}; | |
27728 | + | |
27729 | +module_usb_driver(sr9700_usb_driver); | |
27730 | + | |
27731 | +MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>"); | |
27732 | +MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/"); | |
27733 | +MODULE_LICENSE("GPL"); | |
27734 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/sr9700.h backports-3.18.1-1/drivers/net/usb/sr9700.h | |
27735 | --- backports-3.18.1-1.org/drivers/net/usb/sr9700.h 1970-01-01 01:00:00.000000000 +0100 | |
27736 | +++ backports-3.18.1-1/drivers/net/usb/sr9700.h 2014-12-16 18:39:45.000000000 +0100 | |
27737 | @@ -0,0 +1,173 @@ | |
27738 | +/* | |
27739 | + * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices | |
27740 | + * | |
27741 | + * Author : Liu Junliang <liujunliang_ljl@163.com> | |
27742 | + * | |
27743 | + * This program is free software; you can redistribute it and/or | |
27744 | + * modify it under the terms of the GNU General Public License | |
27745 | + * version 2 as published by the Free Software Foundation. | |
27746 | + */ | |
27747 | + | |
27748 | +#ifndef _SR9700_H | |
27749 | +#define _SR9700_H | |
27750 | + | |
27751 | +/* sr9700 spec. register table on Linux platform */ | |
27752 | + | |
27753 | +/* Network Control Reg */ | |
27754 | +#define NCR 0x00 | |
27755 | +#define NCR_RST (1 << 0) | |
27756 | +#define NCR_LBK (3 << 1) | |
27757 | +#define NCR_FDX (1 << 3) | |
27758 | +#define NCR_WAKEEN (1 << 6) | |
27759 | +/* Network Status Reg */ | |
27760 | +#define NSR 0x01 | |
27761 | +#define NSR_RXRDY (1 << 0) | |
27762 | +#define NSR_RXOV (1 << 1) | |
27763 | +#define NSR_TX1END (1 << 2) | |
27764 | +#define NSR_TX2END (1 << 3) | |
27765 | +#define NSR_TXFULL (1 << 4) | |
27766 | +#define NSR_WAKEST (1 << 5) | |
27767 | +#define NSR_LINKST (1 << 6) | |
27768 | +#define NSR_SPEED (1 << 7) | |
27769 | +/* Tx Control Reg */ | |
27770 | +#define TCR 0x02 | |
27771 | +#define TCR_CRC_DIS (1 << 1) | |
27772 | +#define TCR_PAD_DIS (1 << 2) | |
27773 | +#define TCR_LC_CARE (1 << 3) | |
27774 | +#define TCR_CRS_CARE (1 << 4) | |
27775 | +#define TCR_EXCECM (1 << 5) | |
27776 | +#define TCR_LF_EN (1 << 6) | |
27777 | +/* Tx Status Reg for Packet Index 1 */ | |
27778 | +#define TSR1 0x03 | |
27779 | +#define TSR1_EC (1 << 2) | |
27780 | +#define TSR1_COL (1 << 3) | |
27781 | +#define TSR1_LC (1 << 4) | |
27782 | +#define TSR1_NC (1 << 5) | |
27783 | +#define TSR1_LOC (1 << 6) | |
27784 | +#define TSR1_TLF (1 << 7) | |
27785 | +/* Tx Status Reg for Packet Index 2 */ | |
27786 | +#define TSR2 0x04 | |
27787 | +#define TSR2_EC (1 << 2) | |
27788 | +#define TSR2_COL (1 << 3) | |
27789 | +#define TSR2_LC (1 << 4) | |
27790 | +#define TSR2_NC (1 << 5) | |
27791 | +#define TSR2_LOC (1 << 6) | |
27792 | +#define TSR2_TLF (1 << 7) | |
27793 | +/* Rx Control Reg*/ | |
27794 | +#define RCR 0x05 | |
27795 | +#define RCR_RXEN (1 << 0) | |
27796 | +#define RCR_PRMSC (1 << 1) | |
27797 | +#define RCR_RUNT (1 << 2) | |
27798 | +#define RCR_ALL (1 << 3) | |
27799 | +#define RCR_DIS_CRC (1 << 4) | |
27800 | +#define RCR_DIS_LONG (1 << 5) | |
27801 | +/* Rx Status Reg */ | |
27802 | +#define RSR 0x06 | |
27803 | +#define RSR_AE (1 << 2) | |
27804 | +#define RSR_MF (1 << 6) | |
27805 | +#define RSR_RF (1 << 7) | |
27806 | +/* Rx Overflow Counter Reg */ | |
27807 | +#define ROCR 0x07 | |
27808 | +#define ROCR_ROC (0x7F << 0) | |
27809 | +#define ROCR_RXFU (1 << 7) | |
27810 | +/* Back Pressure Threshold Reg */ | |
27811 | +#define BPTR 0x08 | |
27812 | +#define BPTR_JPT (0x0F << 0) | |
27813 | +#define BPTR_BPHW (0x0F << 4) | |
27814 | +/* Flow Control Threshold Reg */ | |
27815 | +#define FCTR 0x09 | |
27816 | +#define FCTR_LWOT (0x0F << 0) | |
27817 | +#define FCTR_HWOT (0x0F << 4) | |
27818 | +/* rx/tx Flow Control Reg */ | |
27819 | +#define FCR 0x0A | |
27820 | +#define FCR_FLCE (1 << 0) | |
27821 | +#define FCR_BKPA (1 << 4) | |
27822 | +#define FCR_TXPEN (1 << 5) | |
27823 | +#define FCR_TXPF (1 << 6) | |
27824 | +#define FCR_TXP0 (1 << 7) | |
27825 | +/* Eeprom & Phy Control Reg */ | |
27826 | +#define EPCR 0x0B | |
27827 | +#define EPCR_ERRE (1 << 0) | |
27828 | +#define EPCR_ERPRW (1 << 1) | |
27829 | +#define EPCR_ERPRR (1 << 2) | |
27830 | +#define EPCR_EPOS (1 << 3) | |
27831 | +#define EPCR_WEP (1 << 4) | |
27832 | +/* Eeprom & Phy Address Reg */ | |
27833 | +#define EPAR 0x0C | |
27834 | +#define EPAR_EROA (0x3F << 0) | |
27835 | +#define EPAR_PHY_ADR_MASK (0x03 << 6) | |
27836 | +#define EPAR_PHY_ADR (0x01 << 6) | |
27837 | +/* Eeprom & Phy Data Reg */ | |
27838 | +#define EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */ | |
27839 | +/* Wakeup Control Reg */ | |
27840 | +#define WCR 0x0F | |
27841 | +#define WCR_MAGICST (1 << 0) | |
27842 | +#define WCR_LINKST (1 << 2) | |
27843 | +#define WCR_MAGICEN (1 << 3) | |
27844 | +#define WCR_LINKEN (1 << 5) | |
27845 | +/* Physical Address Reg */ | |
27846 | +#define PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */ | |
27847 | +/* Multicast Address Reg */ | |
27848 | +#define MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */ | |
27849 | +/* 0x1e unused */ | |
27850 | +/* Phy Reset Reg */ | |
27851 | +#define PRR 0x1F | |
27852 | +#define PRR_PHY_RST (1 << 0) | |
27853 | +/* Tx sdram Write Pointer Address Low */ | |
27854 | +#define TWPAL 0x20 | |
27855 | +/* Tx sdram Write Pointer Address High */ | |
27856 | +#define TWPAH 0x21 | |
27857 | +/* Tx sdram Read Pointer Address Low */ | |
27858 | +#define TRPAL 0x22 | |
27859 | +/* Tx sdram Read Pointer Address High */ | |
27860 | +#define TRPAH 0x23 | |
27861 | +/* Rx sdram Write Pointer Address Low */ | |
27862 | +#define RWPAL 0x24 | |
27863 | +/* Rx sdram Write Pointer Address High */ | |
27864 | +#define RWPAH 0x25 | |
27865 | +/* Rx sdram Read Pointer Address Low */ | |
27866 | +#define RRPAL 0x26 | |
27867 | +/* Rx sdram Read Pointer Address High */ | |
27868 | +#define RRPAH 0x27 | |
27869 | +/* Vendor ID register */ | |
27870 | +#define VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */ | |
27871 | +/* Product ID register */ | |
27872 | +#define PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */ | |
27873 | +/* CHIP Revision register */ | |
27874 | +#define CHIPR 0x2C | |
27875 | +/* 0x2D --> 0xEF unused */ | |
27876 | +/* USB Device Address */ | |
27877 | +#define USBDA 0xF0 | |
27878 | +#define USBDA_USBFA (0x7F << 0) | |
27879 | +/* RX packet Counter Reg */ | |
27880 | +#define RXC 0xF1 | |
27881 | +/* Tx packet Counter & USB Status Reg */ | |
27882 | +#define TXC_USBS 0xF2 | |
27883 | +#define TXC_USBS_TXC0 (1 << 0) | |
27884 | +#define TXC_USBS_TXC1 (1 << 1) | |
27885 | +#define TXC_USBS_TXC2 (1 << 2) | |
27886 | +#define TXC_USBS_EP1RDY (1 << 5) | |
27887 | +#define TXC_USBS_SUSFLAG (1 << 6) | |
27888 | +#define TXC_USBS_RXFAULT (1 << 7) | |
27889 | +/* USB Control register */ | |
27890 | +#define USBC 0xF4 | |
27891 | +#define USBC_EP3NAK (1 << 4) | |
27892 | +#define USBC_EP3ACK (1 << 5) | |
27893 | + | |
27894 | +/* Register access commands and flags */ | |
27895 | +#define SR_RD_REGS 0x00 | |
27896 | +#define SR_WR_REGS 0x01 | |
27897 | +#define SR_WR_REG 0x03 | |
27898 | +#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) | |
27899 | +#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) | |
27900 | + | |
27901 | +/* parameters */ | |
27902 | +#define SR_SHARE_TIMEOUT 1000 | |
27903 | +#define SR_EEPROM_LEN 256 | |
27904 | +#define SR_MCAST_SIZE 8 | |
27905 | +#define SR_MCAST_ADDR_FLAG 0x80 | |
27906 | +#define SR_MCAST_MAX 64 | |
27907 | +#define SR_TX_OVERHEAD 2 /* 2bytes header */ | |
27908 | +#define SR_RX_OVERHEAD 7 /* 3bytes header + 4crc tail */ | |
27909 | + | |
27910 | +#endif /* _SR9700_H */ | |
27911 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/sr9800.c backports-3.18.1-1/drivers/net/usb/sr9800.c | |
27912 | --- backports-3.18.1-1.org/drivers/net/usb/sr9800.c 1970-01-01 01:00:00.000000000 +0100 | |
27913 | +++ backports-3.18.1-1/drivers/net/usb/sr9800.c 2014-12-16 18:39:45.000000000 +0100 | |
27914 | @@ -0,0 +1,874 @@ | |
27915 | +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices | |
27916 | + * | |
27917 | + * Author : Liu Junliang <liujunliang_ljl@163.com> | |
27918 | + * | |
27919 | + * Based on asix_common.c, asix_devices.c | |
27920 | + * | |
27921 | + * This file is licensed under the terms of the GNU General Public License | |
27922 | + * version 2. This program is licensed "as is" without any warranty of any | |
27923 | + * kind, whether express or implied.* | |
27924 | + */ | |
27925 | + | |
27926 | +#include <linux/module.h> | |
27927 | +#include <linux/kmod.h> | |
27928 | +#include <linux/init.h> | |
27929 | +#include <linux/netdevice.h> | |
27930 | +#include <linux/etherdevice.h> | |
27931 | +#include <linux/ethtool.h> | |
27932 | +#include <linux/workqueue.h> | |
27933 | +#include <linux/mii.h> | |
27934 | +#include <linux/usb.h> | |
27935 | +#include <linux/crc32.h> | |
27936 | +#include <linux/usb/usbnet.h> | |
27937 | +#include <linux/slab.h> | |
27938 | +#include <linux/if_vlan.h> | |
27939 | + | |
27940 | +#include "sr9800.h" | |
27941 | + | |
27942 | +static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
27943 | + u16 size, void *data) | |
27944 | +{ | |
27945 | + int err; | |
27946 | + | |
27947 | + err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index, | |
27948 | + data, size); | |
27949 | + if ((err != size) && (err >= 0)) | |
27950 | + err = -EINVAL; | |
27951 | + | |
27952 | + return err; | |
27953 | +} | |
27954 | + | |
27955 | +static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
27956 | + u16 size, void *data) | |
27957 | +{ | |
27958 | + int err; | |
27959 | + | |
27960 | + err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index, | |
27961 | + data, size); | |
27962 | + if ((err != size) && (err >= 0)) | |
27963 | + err = -EINVAL; | |
27964 | + | |
27965 | + return err; | |
27966 | +} | |
27967 | + | |
27968 | +static void | |
27969 | +sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, | |
27970 | + u16 size, void *data) | |
27971 | +{ | |
27972 | + usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data, | |
27973 | + size); | |
27974 | +} | |
27975 | + | |
27976 | +static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |
27977 | +{ | |
27978 | + int offset = 0; | |
27979 | + | |
27980 | + /* This check is no longer done by usbnet */ | |
27981 | + if (skb->len < dev->net->hard_header_len) | |
27982 | + return 0; | |
27983 | + | |
27984 | + while (offset + sizeof(u32) < skb->len) { | |
27985 | + struct sk_buff *sr_skb; | |
27986 | + u16 size; | |
27987 | + u32 header = get_unaligned_le32(skb->data + offset); | |
27988 | + | |
27989 | + offset += sizeof(u32); | |
27990 | + /* get the packet length */ | |
27991 | + size = (u16) (header & 0x7ff); | |
27992 | + if (size != ((~header >> 16) & 0x07ff)) { | |
27993 | + netdev_err(dev->net, "%s : Bad Header Length\n", | |
27994 | + __func__); | |
27995 | + return 0; | |
27996 | + } | |
27997 | + | |
27998 | + if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || | |
27999 | + (size + offset > skb->len)) { | |
28000 | + netdev_err(dev->net, "%s : Bad RX Length %d\n", | |
28001 | + __func__, size); | |
28002 | + return 0; | |
28003 | + } | |
28004 | + sr_skb = netdev_alloc_skb_ip_align(dev->net, size); | |
28005 | + if (!sr_skb) | |
28006 | + return 0; | |
28007 | + | |
28008 | + skb_put(sr_skb, size); | |
28009 | + memcpy(sr_skb->data, skb->data + offset, size); | |
28010 | + usbnet_skb_return(dev, sr_skb); | |
28011 | + | |
28012 | + offset += (size + 1) & 0xfffe; | |
28013 | + } | |
28014 | + | |
28015 | + if (skb->len != offset) { | |
28016 | + netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__, | |
28017 | + skb->len); | |
28018 | + return 0; | |
28019 | + } | |
28020 | + | |
28021 | + return 1; | |
28022 | +} | |
28023 | + | |
28024 | +static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |
28025 | + gfp_t flags) | |
28026 | +{ | |
28027 | + int headroom = skb_headroom(skb); | |
28028 | + int tailroom = skb_tailroom(skb); | |
28029 | + u32 padbytes = 0xffff0000; | |
28030 | + u32 packet_len; | |
28031 | + int padlen; | |
28032 | + | |
28033 | + padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4; | |
28034 | + | |
28035 | + if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { | |
28036 | + if ((headroom < 4) || (tailroom < padlen)) { | |
28037 | + skb->data = memmove(skb->head + 4, skb->data, | |
28038 | + skb->len); | |
28039 | + skb_set_tail_pointer(skb, skb->len); | |
28040 | + } | |
28041 | + } else { | |
28042 | + struct sk_buff *skb2; | |
28043 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); | |
28044 | + dev_kfree_skb_any(skb); | |
28045 | + skb = skb2; | |
28046 | + if (!skb) | |
28047 | + return NULL; | |
28048 | + } | |
28049 | + | |
28050 | + skb_push(skb, 4); | |
28051 | + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); | |
28052 | + cpu_to_le32s(&packet_len); | |
28053 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); | |
28054 | + | |
28055 | + if (padlen) { | |
28056 | + cpu_to_le32s(&padbytes); | |
28057 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); | |
28058 | + skb_put(skb, sizeof(padbytes)); | |
28059 | + } | |
28060 | + | |
28061 | + return skb; | |
28062 | +} | |
28063 | + | |
28064 | +static void sr_status(struct usbnet *dev, struct urb *urb) | |
28065 | +{ | |
28066 | + struct sr9800_int_data *event; | |
28067 | + int link; | |
28068 | + | |
28069 | + if (urb->actual_length < 8) | |
28070 | + return; | |
28071 | + | |
28072 | + event = urb->transfer_buffer; | |
28073 | + link = event->link & 0x01; | |
28074 | + if (netif_carrier_ok(dev->net) != link) { | |
28075 | + usbnet_link_change(dev, link, 1); | |
28076 | + netdev_dbg(dev->net, "Link Status is: %d\n", link); | |
28077 | + } | |
28078 | + | |
28079 | + return; | |
28080 | +} | |
28081 | + | |
28082 | +static inline int sr_set_sw_mii(struct usbnet *dev) | |
28083 | +{ | |
28084 | + int ret; | |
28085 | + | |
28086 | + ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); | |
28087 | + if (ret < 0) | |
28088 | + netdev_err(dev->net, "Failed to enable software MII access\n"); | |
28089 | + return ret; | |
28090 | +} | |
28091 | + | |
28092 | +static inline int sr_set_hw_mii(struct usbnet *dev) | |
28093 | +{ | |
28094 | + int ret; | |
28095 | + | |
28096 | + ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); | |
28097 | + if (ret < 0) | |
28098 | + netdev_err(dev->net, "Failed to enable hardware MII access\n"); | |
28099 | + return ret; | |
28100 | +} | |
28101 | + | |
28102 | +static inline int sr_get_phy_addr(struct usbnet *dev) | |
28103 | +{ | |
28104 | + u8 buf[2]; | |
28105 | + int ret; | |
28106 | + | |
28107 | + ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf); | |
28108 | + if (ret < 0) { | |
28109 | + netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n", | |
28110 | + __func__, ret); | |
28111 | + goto out; | |
28112 | + } | |
28113 | + netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__, | |
28114 | + *((__le16 *)buf)); | |
28115 | + | |
28116 | + ret = buf[1]; | |
28117 | + | |
28118 | +out: | |
28119 | + return ret; | |
28120 | +} | |
28121 | + | |
28122 | +static int sr_sw_reset(struct usbnet *dev, u8 flags) | |
28123 | +{ | |
28124 | + int ret; | |
28125 | + | |
28126 | + ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL); | |
28127 | + if (ret < 0) | |
28128 | + netdev_err(dev->net, "Failed to send software reset:%02x\n", | |
28129 | + ret); | |
28130 | + | |
28131 | + return ret; | |
28132 | +} | |
28133 | + | |
28134 | +static u16 sr_read_rx_ctl(struct usbnet *dev) | |
28135 | +{ | |
28136 | + __le16 v; | |
28137 | + int ret; | |
28138 | + | |
28139 | + ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v); | |
28140 | + if (ret < 0) { | |
28141 | + netdev_err(dev->net, "Error reading RX_CTL register:%02x\n", | |
28142 | + ret); | |
28143 | + goto out; | |
28144 | + } | |
28145 | + | |
28146 | + ret = le16_to_cpu(v); | |
28147 | +out: | |
28148 | + return ret; | |
28149 | +} | |
28150 | + | |
28151 | +static int sr_write_rx_ctl(struct usbnet *dev, u16 mode) | |
28152 | +{ | |
28153 | + int ret; | |
28154 | + | |
28155 | + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); | |
28156 | + ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); | |
28157 | + if (ret < 0) | |
28158 | + netdev_err(dev->net, | |
28159 | + "Failed to write RX_CTL mode to 0x%04x:%02x\n", | |
28160 | + mode, ret); | |
28161 | + | |
28162 | + return ret; | |
28163 | +} | |
28164 | + | |
28165 | +static u16 sr_read_medium_status(struct usbnet *dev) | |
28166 | +{ | |
28167 | + __le16 v; | |
28168 | + int ret; | |
28169 | + | |
28170 | + ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); | |
28171 | + if (ret < 0) { | |
28172 | + netdev_err(dev->net, | |
28173 | + "Error reading Medium Status register:%02x\n", ret); | |
28174 | + return ret; /* TODO: callers not checking for error ret */ | |
28175 | + } | |
28176 | + | |
28177 | + return le16_to_cpu(v); | |
28178 | +} | |
28179 | + | |
28180 | +static int sr_write_medium_mode(struct usbnet *dev, u16 mode) | |
28181 | +{ | |
28182 | + int ret; | |
28183 | + | |
28184 | + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); | |
28185 | + ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); | |
28186 | + if (ret < 0) | |
28187 | + netdev_err(dev->net, | |
28188 | + "Failed to write Medium Mode mode to 0x%04x:%02x\n", | |
28189 | + mode, ret); | |
28190 | + return ret; | |
28191 | +} | |
28192 | + | |
28193 | +static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep) | |
28194 | +{ | |
28195 | + int ret; | |
28196 | + | |
28197 | + netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value); | |
28198 | + ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL); | |
28199 | + if (ret < 0) | |
28200 | + netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n", | |
28201 | + value, ret); | |
28202 | + if (sleep) | |
28203 | + msleep(sleep); | |
28204 | + | |
28205 | + return ret; | |
28206 | +} | |
28207 | + | |
28208 | +/* SR9800 have a 16-bit RX_CTL value */ | |
28209 | +static void sr_set_multicast(struct net_device *net) | |
28210 | +{ | |
28211 | + struct usbnet *dev = netdev_priv(net); | |
28212 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28213 | + u16 rx_ctl = SR_DEFAULT_RX_CTL; | |
28214 | + | |
28215 | + if (net->flags & IFF_PROMISC) { | |
28216 | + rx_ctl |= SR_RX_CTL_PRO; | |
28217 | + } else if (net->flags & IFF_ALLMULTI || | |
28218 | + netdev_mc_count(net) > SR_MAX_MCAST) { | |
28219 | + rx_ctl |= SR_RX_CTL_AMALL; | |
28220 | + } else if (netdev_mc_empty(net)) { | |
28221 | + /* just broadcast and directed */ | |
28222 | + } else { | |
28223 | + /* We use the 20 byte dev->data | |
28224 | + * for our 8 byte filter buffer | |
28225 | + * to avoid allocating memory that | |
28226 | + * is tricky to free later | |
28227 | + */ | |
28228 | + struct netdev_hw_addr *ha; | |
28229 | + u32 crc_bits; | |
28230 | + | |
28231 | + memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE); | |
28232 | + | |
28233 | + /* Build the multicast hash filter. */ | |
28234 | + netdev_for_each_mc_addr(ha, net) { | |
28235 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; | |
28236 | + data->multi_filter[crc_bits >> 3] |= | |
28237 | + 1 << (crc_bits & 7); | |
28238 | + } | |
28239 | + | |
28240 | + sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0, | |
28241 | + SR_MCAST_FILTER_SIZE, data->multi_filter); | |
28242 | + | |
28243 | + rx_ctl |= SR_RX_CTL_AM; | |
28244 | + } | |
28245 | + | |
28246 | + sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); | |
28247 | +} | |
28248 | + | |
28249 | +static int sr_mdio_read(struct net_device *net, int phy_id, int loc) | |
28250 | +{ | |
28251 | + struct usbnet *dev = netdev_priv(net); | |
28252 | + __le16 res; | |
28253 | + | |
28254 | + mutex_lock(&dev->phy_mutex); | |
28255 | + sr_set_sw_mii(dev); | |
28256 | + sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res); | |
28257 | + sr_set_hw_mii(dev); | |
28258 | + mutex_unlock(&dev->phy_mutex); | |
28259 | + | |
28260 | + netdev_dbg(dev->net, | |
28261 | + "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__, | |
28262 | + phy_id, loc, le16_to_cpu(res)); | |
28263 | + | |
28264 | + return le16_to_cpu(res); | |
28265 | +} | |
28266 | + | |
28267 | +static void | |
28268 | +sr_mdio_write(struct net_device *net, int phy_id, int loc, int val) | |
28269 | +{ | |
28270 | + struct usbnet *dev = netdev_priv(net); | |
28271 | + __le16 res = cpu_to_le16(val); | |
28272 | + | |
28273 | + netdev_dbg(dev->net, | |
28274 | + "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__, | |
28275 | + phy_id, loc, val); | |
28276 | + mutex_lock(&dev->phy_mutex); | |
28277 | + sr_set_sw_mii(dev); | |
28278 | + sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); | |
28279 | + sr_set_hw_mii(dev); | |
28280 | + mutex_unlock(&dev->phy_mutex); | |
28281 | +} | |
28282 | + | |
28283 | +/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ | |
28284 | +static u32 sr_get_phyid(struct usbnet *dev) | |
28285 | +{ | |
28286 | + int phy_reg; | |
28287 | + u32 phy_id; | |
28288 | + int i; | |
28289 | + | |
28290 | + /* Poll for the rare case the FW or phy isn't ready yet. */ | |
28291 | + for (i = 0; i < 100; i++) { | |
28292 | + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); | |
28293 | + if (phy_reg != 0 && phy_reg != 0xFFFF) | |
28294 | + break; | |
28295 | + mdelay(1); | |
28296 | + } | |
28297 | + | |
28298 | + if (phy_reg <= 0 || phy_reg == 0xFFFF) | |
28299 | + return 0; | |
28300 | + | |
28301 | + phy_id = (phy_reg & 0xffff) << 16; | |
28302 | + | |
28303 | + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); | |
28304 | + if (phy_reg < 0) | |
28305 | + return 0; | |
28306 | + | |
28307 | + phy_id |= (phy_reg & 0xffff); | |
28308 | + | |
28309 | + return phy_id; | |
28310 | +} | |
28311 | + | |
28312 | +static void | |
28313 | +sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
28314 | +{ | |
28315 | + struct usbnet *dev = netdev_priv(net); | |
28316 | + u8 opt; | |
28317 | + | |
28318 | + if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { | |
28319 | + wolinfo->supported = 0; | |
28320 | + wolinfo->wolopts = 0; | |
28321 | + return; | |
28322 | + } | |
28323 | + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | |
28324 | + wolinfo->wolopts = 0; | |
28325 | + if (opt & SR_MONITOR_LINK) | |
28326 | + wolinfo->wolopts |= WAKE_PHY; | |
28327 | + if (opt & SR_MONITOR_MAGIC) | |
28328 | + wolinfo->wolopts |= WAKE_MAGIC; | |
28329 | +} | |
28330 | + | |
28331 | +static int | |
28332 | +sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) | |
28333 | +{ | |
28334 | + struct usbnet *dev = netdev_priv(net); | |
28335 | + u8 opt = 0; | |
28336 | + | |
28337 | + if (wolinfo->wolopts & WAKE_PHY) | |
28338 | + opt |= SR_MONITOR_LINK; | |
28339 | + if (wolinfo->wolopts & WAKE_MAGIC) | |
28340 | + opt |= SR_MONITOR_MAGIC; | |
28341 | + | |
28342 | + if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE, | |
28343 | + opt, 0, 0, NULL) < 0) | |
28344 | + return -EINVAL; | |
28345 | + | |
28346 | + return 0; | |
28347 | +} | |
28348 | + | |
28349 | +static int sr_get_eeprom_len(struct net_device *net) | |
28350 | +{ | |
28351 | + struct usbnet *dev = netdev_priv(net); | |
28352 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28353 | + | |
28354 | + return data->eeprom_len; | |
28355 | +} | |
28356 | + | |
28357 | +static int sr_get_eeprom(struct net_device *net, | |
28358 | + struct ethtool_eeprom *eeprom, u8 *data) | |
28359 | +{ | |
28360 | + struct usbnet *dev = netdev_priv(net); | |
28361 | + __le16 *ebuf = (__le16 *)data; | |
28362 | + int ret; | |
28363 | + int i; | |
28364 | + | |
28365 | + /* Crude hack to ensure that we don't overwrite memory | |
28366 | + * if an odd length is supplied | |
28367 | + */ | |
28368 | + if (eeprom->len % 2) | |
28369 | + return -EINVAL; | |
28370 | + | |
28371 | + eeprom->magic = SR_EEPROM_MAGIC; | |
28372 | + | |
28373 | + /* sr9800 returns 2 bytes from eeprom on read */ | |
28374 | + for (i = 0; i < eeprom->len / 2; i++) { | |
28375 | + ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i, | |
28376 | + 0, 2, &ebuf[i]); | |
28377 | + if (ret < 0) | |
28378 | + return -EINVAL; | |
28379 | + } | |
28380 | + return 0; | |
28381 | +} | |
28382 | + | |
28383 | +static void sr_get_drvinfo(struct net_device *net, | |
28384 | + struct ethtool_drvinfo *info) | |
28385 | +{ | |
28386 | + struct usbnet *dev = netdev_priv(net); | |
28387 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28388 | + | |
28389 | + /* Inherit standard device info */ | |
28390 | + usbnet_get_drvinfo(net, info); | |
28391 | + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); | |
28392 | + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); | |
28393 | + info->eedump_len = data->eeprom_len; | |
28394 | +} | |
28395 | + | |
28396 | +static u32 sr_get_link(struct net_device *net) | |
28397 | +{ | |
28398 | + struct usbnet *dev = netdev_priv(net); | |
28399 | + | |
28400 | + return mii_link_ok(&dev->mii); | |
28401 | +} | |
28402 | + | |
28403 | +static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd) | |
28404 | +{ | |
28405 | + struct usbnet *dev = netdev_priv(net); | |
28406 | + | |
28407 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
28408 | +} | |
28409 | + | |
28410 | +static int sr_set_mac_address(struct net_device *net, void *p) | |
28411 | +{ | |
28412 | + struct usbnet *dev = netdev_priv(net); | |
28413 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28414 | + struct sockaddr *addr = p; | |
28415 | + | |
28416 | + if (netif_running(net)) | |
28417 | + return -EBUSY; | |
28418 | + if (!is_valid_ether_addr(addr->sa_data)) | |
28419 | + return -EADDRNOTAVAIL; | |
28420 | + | |
28421 | + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); | |
28422 | + | |
28423 | + /* We use the 20 byte dev->data | |
28424 | + * for our 6 byte mac buffer | |
28425 | + * to avoid allocating memory that | |
28426 | + * is tricky to free later | |
28427 | + */ | |
28428 | + memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); | |
28429 | + sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
28430 | + data->mac_addr); | |
28431 | + | |
28432 | + return 0; | |
28433 | +} | |
28434 | + | |
28435 | +static const struct ethtool_ops sr9800_ethtool_ops = { | |
28436 | + .get_drvinfo = sr_get_drvinfo, | |
28437 | + .get_link = sr_get_link, | |
28438 | + .get_msglevel = usbnet_get_msglevel, | |
28439 | + .set_msglevel = usbnet_set_msglevel, | |
28440 | + .get_wol = sr_get_wol, | |
28441 | + .set_wol = sr_set_wol, | |
28442 | + .get_eeprom_len = sr_get_eeprom_len, | |
28443 | + .get_eeprom = sr_get_eeprom, | |
28444 | + .get_settings = usbnet_get_settings, | |
28445 | + .set_settings = usbnet_set_settings, | |
28446 | + .nway_reset = usbnet_nway_reset, | |
28447 | +}; | |
28448 | + | |
28449 | +static int sr9800_link_reset(struct usbnet *dev) | |
28450 | +{ | |
28451 | + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; | |
28452 | + u16 mode; | |
28453 | + | |
28454 | + mii_check_media(&dev->mii, 1, 1); | |
28455 | + mii_ethtool_gset(&dev->mii, &ecmd); | |
28456 | + mode = SR9800_MEDIUM_DEFAULT; | |
28457 | + | |
28458 | + if (ethtool_cmd_speed(&ecmd) != SPEED_100) | |
28459 | + mode &= ~SR_MEDIUM_PS; | |
28460 | + | |
28461 | + if (ecmd.duplex != DUPLEX_FULL) | |
28462 | + mode &= ~SR_MEDIUM_FD; | |
28463 | + | |
28464 | + netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n", | |
28465 | + __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); | |
28466 | + | |
28467 | + sr_write_medium_mode(dev, mode); | |
28468 | + | |
28469 | + return 0; | |
28470 | +} | |
28471 | + | |
28472 | + | |
28473 | +static int sr9800_set_default_mode(struct usbnet *dev) | |
28474 | +{ | |
28475 | + u16 rx_ctl; | |
28476 | + int ret; | |
28477 | + | |
28478 | + sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); | |
28479 | + sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, | |
28480 | + ADVERTISE_ALL | ADVERTISE_CSMA); | |
28481 | + mii_nway_restart(&dev->mii); | |
28482 | + | |
28483 | + ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT); | |
28484 | + if (ret < 0) | |
28485 | + goto out; | |
28486 | + | |
28487 | + ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012, | |
28488 | + SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT, | |
28489 | + SR9800_IPG2_DEFAULT, 0, NULL); | |
28490 | + if (ret < 0) { | |
28491 | + netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); | |
28492 | + goto out; | |
28493 | + } | |
28494 | + | |
28495 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ | |
28496 | + ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL); | |
28497 | + if (ret < 0) | |
28498 | + goto out; | |
28499 | + | |
28500 | + rx_ctl = sr_read_rx_ctl(dev); | |
28501 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", | |
28502 | + rx_ctl); | |
28503 | + | |
28504 | + rx_ctl = sr_read_medium_status(dev); | |
28505 | + netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n", | |
28506 | + rx_ctl); | |
28507 | + | |
28508 | + return 0; | |
28509 | +out: | |
28510 | + return ret; | |
28511 | +} | |
28512 | + | |
28513 | +static int sr9800_reset(struct usbnet *dev) | |
28514 | +{ | |
28515 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28516 | + int ret, embd_phy; | |
28517 | + u16 rx_ctl; | |
28518 | + | |
28519 | + ret = sr_write_gpio(dev, | |
28520 | + SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5); | |
28521 | + if (ret < 0) | |
28522 | + goto out; | |
28523 | + | |
28524 | + embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); | |
28525 | + | |
28526 | + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | |
28527 | + if (ret < 0) { | |
28528 | + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | |
28529 | + goto out; | |
28530 | + } | |
28531 | + | |
28532 | + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL); | |
28533 | + if (ret < 0) | |
28534 | + goto out; | |
28535 | + | |
28536 | + msleep(150); | |
28537 | + | |
28538 | + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); | |
28539 | + if (ret < 0) | |
28540 | + goto out; | |
28541 | + | |
28542 | + msleep(150); | |
28543 | + | |
28544 | + if (embd_phy) { | |
28545 | + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | |
28546 | + if (ret < 0) | |
28547 | + goto out; | |
28548 | + } else { | |
28549 | + ret = sr_sw_reset(dev, SR_SWRESET_PRTE); | |
28550 | + if (ret < 0) | |
28551 | + goto out; | |
28552 | + } | |
28553 | + | |
28554 | + msleep(150); | |
28555 | + rx_ctl = sr_read_rx_ctl(dev); | |
28556 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | |
28557 | + ret = sr_write_rx_ctl(dev, 0x0000); | |
28558 | + if (ret < 0) | |
28559 | + goto out; | |
28560 | + | |
28561 | + rx_ctl = sr_read_rx_ctl(dev); | |
28562 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | |
28563 | + | |
28564 | + ret = sr_sw_reset(dev, SR_SWRESET_PRL); | |
28565 | + if (ret < 0) | |
28566 | + goto out; | |
28567 | + | |
28568 | + msleep(150); | |
28569 | + | |
28570 | + ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL); | |
28571 | + if (ret < 0) | |
28572 | + goto out; | |
28573 | + | |
28574 | + msleep(150); | |
28575 | + | |
28576 | + ret = sr9800_set_default_mode(dev); | |
28577 | + if (ret < 0) | |
28578 | + goto out; | |
28579 | + | |
28580 | + /* Rewrite MAC address */ | |
28581 | + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); | |
28582 | + ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, | |
28583 | + data->mac_addr); | |
28584 | + if (ret < 0) | |
28585 | + goto out; | |
28586 | + | |
28587 | + return 0; | |
28588 | + | |
28589 | +out: | |
28590 | + return ret; | |
28591 | +} | |
28592 | + | |
28593 | +static const struct net_device_ops sr9800_netdev_ops = { | |
28594 | + .ndo_open = usbnet_open, | |
28595 | + .ndo_stop = usbnet_stop, | |
28596 | + .ndo_start_xmit = usbnet_start_xmit, | |
28597 | + .ndo_tx_timeout = usbnet_tx_timeout, | |
28598 | + .ndo_change_mtu = usbnet_change_mtu, | |
28599 | + .ndo_set_mac_address = sr_set_mac_address, | |
28600 | + .ndo_validate_addr = eth_validate_addr, | |
28601 | + .ndo_do_ioctl = sr_ioctl, | |
28602 | + .ndo_set_rx_mode = sr_set_multicast, | |
28603 | +}; | |
28604 | + | |
28605 | +static int sr9800_phy_powerup(struct usbnet *dev) | |
28606 | +{ | |
28607 | + int ret; | |
28608 | + | |
28609 | + /* set the embedded Ethernet PHY in power-down state */ | |
28610 | + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL); | |
28611 | + if (ret < 0) { | |
28612 | + netdev_err(dev->net, "Failed to power down PHY : %d\n", ret); | |
28613 | + return ret; | |
28614 | + } | |
28615 | + msleep(20); | |
28616 | + | |
28617 | + /* set the embedded Ethernet PHY in power-up state */ | |
28618 | + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | |
28619 | + if (ret < 0) { | |
28620 | + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); | |
28621 | + return ret; | |
28622 | + } | |
28623 | + msleep(600); | |
28624 | + | |
28625 | + /* set the embedded Ethernet PHY in reset state */ | |
28626 | + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); | |
28627 | + if (ret < 0) { | |
28628 | + netdev_err(dev->net, "Failed to power up PHY: %d\n", ret); | |
28629 | + return ret; | |
28630 | + } | |
28631 | + msleep(20); | |
28632 | + | |
28633 | + /* set the embedded Ethernet PHY in power-up state */ | |
28634 | + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); | |
28635 | + if (ret < 0) { | |
28636 | + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); | |
28637 | + return ret; | |
28638 | + } | |
28639 | + | |
28640 | + return 0; | |
28641 | +} | |
28642 | + | |
28643 | +static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) | |
28644 | +{ | |
28645 | + struct sr_data *data = (struct sr_data *)&dev->data; | |
28646 | + u16 led01_mux, led23_mux; | |
28647 | + int ret, embd_phy; | |
28648 | + u32 phyid; | |
28649 | + u16 rx_ctl; | |
28650 | + | |
28651 | + data->eeprom_len = SR9800_EEPROM_LEN; | |
28652 | + | |
28653 | + usbnet_get_endpoints(dev, intf); | |
28654 | + | |
28655 | + /* LED Setting Rule : | |
28656 | + * AABB:CCDD | |
28657 | + * AA : MFA0(LED0) | |
28658 | + * BB : MFA1(LED1) | |
28659 | + * CC : MFA2(LED2), Reserved for SR9800 | |
28660 | + * DD : MFA3(LED3), Reserved for SR9800 | |
28661 | + */ | |
28662 | + led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK; | |
28663 | + led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE; | |
28664 | + ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL); | |
28665 | + if (ret < 0) { | |
28666 | + netdev_err(dev->net, "set LINK LED failed : %d\n", ret); | |
28667 | + goto out; | |
28668 | + } | |
28669 | + | |
28670 | + /* Get the MAC address */ | |
28671 | + ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, | |
28672 | + dev->net->dev_addr); | |
28673 | + if (ret < 0) { | |
28674 | + netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); | |
28675 | + return ret; | |
28676 | + } | |
28677 | + netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr); | |
28678 | + | |
28679 | + /* Initialize MII structure */ | |
28680 | + dev->mii.dev = dev->net; | |
28681 | + dev->mii.mdio_read = sr_mdio_read; | |
28682 | + dev->mii.mdio_write = sr_mdio_write; | |
28683 | + dev->mii.phy_id_mask = 0x1f; | |
28684 | + dev->mii.reg_num_mask = 0x1f; | |
28685 | + dev->mii.phy_id = sr_get_phy_addr(dev); | |
28686 | + | |
28687 | + dev->net->netdev_ops = &sr9800_netdev_ops; | |
28688 | + dev->net->ethtool_ops = &sr9800_ethtool_ops; | |
28689 | + | |
28690 | + embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); | |
28691 | + /* Reset the PHY to normal operation mode */ | |
28692 | + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); | |
28693 | + if (ret < 0) { | |
28694 | + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); | |
28695 | + return ret; | |
28696 | + } | |
28697 | + | |
28698 | + /* Init PHY routine */ | |
28699 | + ret = sr9800_phy_powerup(dev); | |
28700 | + if (ret < 0) | |
28701 | + goto out; | |
28702 | + | |
28703 | + rx_ctl = sr_read_rx_ctl(dev); | |
28704 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); | |
28705 | + ret = sr_write_rx_ctl(dev, 0x0000); | |
28706 | + if (ret < 0) | |
28707 | + goto out; | |
28708 | + | |
28709 | + rx_ctl = sr_read_rx_ctl(dev); | |
28710 | + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); | |
28711 | + | |
28712 | + /* Read PHYID register *AFTER* the PHY was reset properly */ | |
28713 | + phyid = sr_get_phyid(dev); | |
28714 | + netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); | |
28715 | + | |
28716 | + /* medium mode setting */ | |
28717 | + ret = sr9800_set_default_mode(dev); | |
28718 | + if (ret < 0) | |
28719 | + goto out; | |
28720 | + | |
28721 | + if (dev->udev->speed == USB_SPEED_HIGH) { | |
28722 | + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, | |
28723 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt, | |
28724 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold, | |
28725 | + 0, NULL); | |
28726 | + if (ret < 0) { | |
28727 | + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); | |
28728 | + goto out; | |
28729 | + } | |
28730 | + dev->rx_urb_size = | |
28731 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size; | |
28732 | + } else { | |
28733 | + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, | |
28734 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt, | |
28735 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold, | |
28736 | + 0, NULL); | |
28737 | + if (ret < 0) { | |
28738 | + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); | |
28739 | + goto out; | |
28740 | + } | |
28741 | + dev->rx_urb_size = | |
28742 | + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size; | |
28743 | + } | |
28744 | + netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__, | |
28745 | + dev->rx_urb_size); | |
28746 | + return 0; | |
28747 | + | |
28748 | +out: | |
28749 | + return ret; | |
28750 | +} | |
28751 | + | |
28752 | +static const struct driver_info sr9800_driver_info = { | |
28753 | + .description = "CoreChip SR9800 USB 2.0 Ethernet", | |
28754 | + .bind = sr9800_bind, | |
28755 | + .status = sr_status, | |
28756 | + .link_reset = sr9800_link_reset, | |
28757 | + .reset = sr9800_reset, | |
28758 | + .flags = DRIVER_FLAG, | |
28759 | + .rx_fixup = sr_rx_fixup, | |
28760 | + .tx_fixup = sr_tx_fixup, | |
28761 | +}; | |
28762 | + | |
28763 | +static const struct usb_device_id products[] = { | |
28764 | + { | |
28765 | + USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */ | |
28766 | + .driver_info = (unsigned long) &sr9800_driver_info, | |
28767 | + }, | |
28768 | + {}, /* END */ | |
28769 | +}; | |
28770 | + | |
28771 | +MODULE_DEVICE_TABLE(usb, products); | |
28772 | + | |
28773 | +static struct usb_driver sr_driver = { | |
28774 | + .name = DRIVER_NAME, | |
28775 | + .id_table = products, | |
28776 | + .probe = usbnet_probe, | |
28777 | + .suspend = usbnet_suspend, | |
28778 | + .resume = usbnet_resume, | |
28779 | + .disconnect = usbnet_disconnect, | |
28780 | + .supports_autosuspend = 1, | |
28781 | +}; | |
28782 | + | |
28783 | +module_usb_driver(sr_driver); | |
28784 | + | |
28785 | +MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com"); | |
28786 | +MODULE_VERSION(DRIVER_VERSION); | |
28787 | +MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com"); | |
28788 | +MODULE_LICENSE("GPL"); | |
28789 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/sr9800.h backports-3.18.1-1/drivers/net/usb/sr9800.h | |
28790 | --- backports-3.18.1-1.org/drivers/net/usb/sr9800.h 1970-01-01 01:00:00.000000000 +0100 | |
28791 | +++ backports-3.18.1-1/drivers/net/usb/sr9800.h 2014-12-16 18:39:45.000000000 +0100 | |
28792 | @@ -0,0 +1,202 @@ | |
28793 | +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices | |
28794 | + * | |
28795 | + * Author : Liu Junliang <liujunliang_ljl@163.com> | |
28796 | + * | |
28797 | + * This file is licensed under the terms of the GNU General Public License | |
28798 | + * version 2. This program is licensed "as is" without any warranty of any | |
28799 | + * kind, whether express or implied. | |
28800 | + */ | |
28801 | + | |
28802 | +#ifndef _SR9800_H | |
28803 | +#define _SR9800_H | |
28804 | + | |
28805 | +/* SR9800 spec. command table on Linux Platform */ | |
28806 | + | |
28807 | +/* command : Software Station Management Control Reg */ | |
28808 | +#define SR_CMD_SET_SW_MII 0x06 | |
28809 | +/* command : PHY Read Reg */ | |
28810 | +#define SR_CMD_READ_MII_REG 0x07 | |
28811 | +/* command : PHY Write Reg */ | |
28812 | +#define SR_CMD_WRITE_MII_REG 0x08 | |
28813 | +/* command : Hardware Station Management Control Reg */ | |
28814 | +#define SR_CMD_SET_HW_MII 0x0a | |
28815 | +/* command : SROM Read Reg */ | |
28816 | +#define SR_CMD_READ_EEPROM 0x0b | |
28817 | +/* command : SROM Write Reg */ | |
28818 | +#define SR_CMD_WRITE_EEPROM 0x0c | |
28819 | +/* command : SROM Write Enable Reg */ | |
28820 | +#define SR_CMD_WRITE_ENABLE 0x0d | |
28821 | +/* command : SROM Write Disable Reg */ | |
28822 | +#define SR_CMD_WRITE_DISABLE 0x0e | |
28823 | +/* command : RX Control Read Reg */ | |
28824 | +#define SR_CMD_READ_RX_CTL 0x0f | |
28825 | +#define SR_RX_CTL_PRO (1 << 0) | |
28826 | +#define SR_RX_CTL_AMALL (1 << 1) | |
28827 | +#define SR_RX_CTL_SEP (1 << 2) | |
28828 | +#define SR_RX_CTL_AB (1 << 3) | |
28829 | +#define SR_RX_CTL_AM (1 << 4) | |
28830 | +#define SR_RX_CTL_AP (1 << 5) | |
28831 | +#define SR_RX_CTL_ARP (1 << 6) | |
28832 | +#define SR_RX_CTL_SO (1 << 7) | |
28833 | +#define SR_RX_CTL_RH1M (1 << 8) | |
28834 | +#define SR_RX_CTL_RH2M (1 << 9) | |
28835 | +#define SR_RX_CTL_RH3M (1 << 10) | |
28836 | +/* command : RX Control Write Reg */ | |
28837 | +#define SR_CMD_WRITE_RX_CTL 0x10 | |
28838 | +/* command : IPG0/IPG1/IPG2 Control Read Reg */ | |
28839 | +#define SR_CMD_READ_IPG012 0x11 | |
28840 | +/* command : IPG0/IPG1/IPG2 Control Write Reg */ | |
28841 | +#define SR_CMD_WRITE_IPG012 0x12 | |
28842 | +/* command : Node ID Read Reg */ | |
28843 | +#define SR_CMD_READ_NODE_ID 0x13 | |
28844 | +/* command : Node ID Write Reg */ | |
28845 | +#define SR_CMD_WRITE_NODE_ID 0x14 | |
28846 | +/* command : Multicast Filter Array Read Reg */ | |
28847 | +#define SR_CMD_READ_MULTI_FILTER 0x15 | |
28848 | +/* command : Multicast Filter Array Write Reg */ | |
28849 | +#define SR_CMD_WRITE_MULTI_FILTER 0x16 | |
28850 | +/* command : Eth/HomePNA PHY Address Reg */ | |
28851 | +#define SR_CMD_READ_PHY_ID 0x19 | |
28852 | +/* command : Medium Status Read Reg */ | |
28853 | +#define SR_CMD_READ_MEDIUM_STATUS 0x1a | |
28854 | +#define SR_MONITOR_LINK (1 << 1) | |
28855 | +#define SR_MONITOR_MAGIC (1 << 2) | |
28856 | +#define SR_MONITOR_HSFS (1 << 4) | |
28857 | +/* command : Medium Status Write Reg */ | |
28858 | +#define SR_CMD_WRITE_MEDIUM_MODE 0x1b | |
28859 | +#define SR_MEDIUM_GM (1 << 0) | |
28860 | +#define SR_MEDIUM_FD (1 << 1) | |
28861 | +#define SR_MEDIUM_AC (1 << 2) | |
28862 | +#define SR_MEDIUM_ENCK (1 << 3) | |
28863 | +#define SR_MEDIUM_RFC (1 << 4) | |
28864 | +#define SR_MEDIUM_TFC (1 << 5) | |
28865 | +#define SR_MEDIUM_JFE (1 << 6) | |
28866 | +#define SR_MEDIUM_PF (1 << 7) | |
28867 | +#define SR_MEDIUM_RE (1 << 8) | |
28868 | +#define SR_MEDIUM_PS (1 << 9) | |
28869 | +#define SR_MEDIUM_RSV (1 << 10) | |
28870 | +#define SR_MEDIUM_SBP (1 << 11) | |
28871 | +#define SR_MEDIUM_SM (1 << 12) | |
28872 | +/* command : Monitor Mode Status Read Reg */ | |
28873 | +#define SR_CMD_READ_MONITOR_MODE 0x1c | |
28874 | +/* command : Monitor Mode Status Write Reg */ | |
28875 | +#define SR_CMD_WRITE_MONITOR_MODE 0x1d | |
28876 | +/* command : GPIO Status Read Reg */ | |
28877 | +#define SR_CMD_READ_GPIOS 0x1e | |
28878 | +#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */ | |
28879 | +#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */ | |
28880 | +#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */ | |
28881 | +#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */ | |
28882 | +#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */ | |
28883 | +#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */ | |
28884 | +#define SR_GPIO_RESERVED (1 << 6) /* Reserved */ | |
28885 | +#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */ | |
28886 | +/* command : GPIO Status Write Reg */ | |
28887 | +#define SR_CMD_WRITE_GPIOS 0x1f | |
28888 | +/* command : Eth PHY Power and Reset Control Reg */ | |
28889 | +#define SR_CMD_SW_RESET 0x20 | |
28890 | +#define SR_SWRESET_CLEAR 0x00 | |
28891 | +#define SR_SWRESET_RR (1 << 0) | |
28892 | +#define SR_SWRESET_RT (1 << 1) | |
28893 | +#define SR_SWRESET_PRTE (1 << 2) | |
28894 | +#define SR_SWRESET_PRL (1 << 3) | |
28895 | +#define SR_SWRESET_BZ (1 << 4) | |
28896 | +#define SR_SWRESET_IPRL (1 << 5) | |
28897 | +#define SR_SWRESET_IPPD (1 << 6) | |
28898 | +/* command : Software Interface Selection Status Read Reg */ | |
28899 | +#define SR_CMD_SW_PHY_STATUS 0x21 | |
28900 | +/* command : Software Interface Selection Status Write Reg */ | |
28901 | +#define SR_CMD_SW_PHY_SELECT 0x22 | |
28902 | +/* command : BULK in Buffer Size Reg */ | |
28903 | +#define SR_CMD_BULKIN_SIZE 0x2A | |
28904 | +/* command : LED_MUX Control Reg */ | |
28905 | +#define SR_CMD_LED_MUX 0x70 | |
28906 | +#define SR_LED_MUX_TX_ACTIVE (1 << 0) | |
28907 | +#define SR_LED_MUX_RX_ACTIVE (1 << 1) | |
28908 | +#define SR_LED_MUX_COLLISION (1 << 2) | |
28909 | +#define SR_LED_MUX_DUP_COL (1 << 3) | |
28910 | +#define SR_LED_MUX_DUP (1 << 4) | |
28911 | +#define SR_LED_MUX_SPEED (1 << 5) | |
28912 | +#define SR_LED_MUX_LINK_ACTIVE (1 << 6) | |
28913 | +#define SR_LED_MUX_LINK (1 << 7) | |
28914 | + | |
28915 | +/* Register Access Flags */ | |
28916 | +#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) | |
28917 | +#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) | |
28918 | + | |
28919 | +/* Multicast Filter Array size & Max Number */ | |
28920 | +#define SR_MCAST_FILTER_SIZE 8 | |
28921 | +#define SR_MAX_MCAST 64 | |
28922 | + | |
28923 | +/* IPG0/1/2 Default Value */ | |
28924 | +#define SR9800_IPG0_DEFAULT 0x15 | |
28925 | +#define SR9800_IPG1_DEFAULT 0x0c | |
28926 | +#define SR9800_IPG2_DEFAULT 0x12 | |
28927 | + | |
28928 | +/* Medium Status Default Mode */ | |
28929 | +#define SR9800_MEDIUM_DEFAULT \ | |
28930 | + (SR_MEDIUM_FD | SR_MEDIUM_RFC | \ | |
28931 | + SR_MEDIUM_TFC | SR_MEDIUM_PS | \ | |
28932 | + SR_MEDIUM_AC | SR_MEDIUM_RE) | |
28933 | + | |
28934 | +/* RX Control Default Setting */ | |
28935 | +#define SR_DEFAULT_RX_CTL \ | |
28936 | + (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M) | |
28937 | + | |
28938 | +/* EEPROM Magic Number & EEPROM Size */ | |
28939 | +#define SR_EEPROM_MAGIC 0xdeadbeef | |
28940 | +#define SR9800_EEPROM_LEN 0xff | |
28941 | + | |
28942 | +/* SR9800 Driver Version and Driver Name */ | |
28943 | +#define DRIVER_VERSION "11-Nov-2013" | |
28944 | +#define DRIVER_NAME "CoreChips" | |
28945 | +#define DRIVER_FLAG \ | |
28946 | + (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET) | |
28947 | + | |
28948 | +/* SR9800 BULKIN Buffer Size */ | |
28949 | +#define SR9800_MAX_BULKIN_2K 0 | |
28950 | +#define SR9800_MAX_BULKIN_4K 1 | |
28951 | +#define SR9800_MAX_BULKIN_6K 2 | |
28952 | +#define SR9800_MAX_BULKIN_8K 3 | |
28953 | +#define SR9800_MAX_BULKIN_16K 4 | |
28954 | +#define SR9800_MAX_BULKIN_20K 5 | |
28955 | +#define SR9800_MAX_BULKIN_24K 6 | |
28956 | +#define SR9800_MAX_BULKIN_32K 7 | |
28957 | + | |
28958 | +struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = { | |
28959 | + /* 2k */ | |
28960 | + {2048, 0x8000, 0x8001}, | |
28961 | + /* 4k */ | |
28962 | + {4096, 0x8100, 0x8147}, | |
28963 | + /* 6k */ | |
28964 | + {6144, 0x8200, 0x81EB}, | |
28965 | + /* 8k */ | |
28966 | + {8192, 0x8300, 0x83D7}, | |
28967 | + /* 16 */ | |
28968 | + {16384, 0x8400, 0x851E}, | |
28969 | + /* 20k */ | |
28970 | + {20480, 0x8500, 0x8666}, | |
28971 | + /* 24k */ | |
28972 | + {24576, 0x8600, 0x87AE}, | |
28973 | + /* 32k */ | |
28974 | + {32768, 0x8700, 0x8A3D}, | |
28975 | +}; | |
28976 | + | |
28977 | +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ | |
28978 | +struct sr_data { | |
28979 | + u8 multi_filter[SR_MCAST_FILTER_SIZE]; | |
28980 | + u8 mac_addr[ETH_ALEN]; | |
28981 | + u8 phymode; | |
28982 | + u8 ledmode; | |
28983 | + u8 eeprom_len; | |
28984 | +}; | |
28985 | + | |
28986 | +struct sr9800_int_data { | |
28987 | + __le16 res1; | |
28988 | + u8 link; | |
28989 | + __le16 res2; | |
28990 | + u8 status; | |
28991 | + __le16 res3; | |
28992 | +} __packed; | |
28993 | + | |
28994 | +#endif /* _SR9800_H */ | |
28995 | diff -Naur backports-3.18.1-1.org/drivers/net/usb/zaurus.c backports-3.18.1-1/drivers/net/usb/zaurus.c | |
28996 | --- backports-3.18.1-1.org/drivers/net/usb/zaurus.c 1970-01-01 01:00:00.000000000 +0100 | |
28997 | +++ backports-3.18.1-1/drivers/net/usb/zaurus.c 2014-12-16 18:39:45.000000000 +0100 | |
28998 | @@ -0,0 +1,385 @@ | |
28999 | +/* | |
29000 | + * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz> | |
29001 | + * Copyright (C) 2002-2005 by David Brownell | |
29002 | + * | |
29003 | + * This program is free software; you can redistribute it and/or modify | |
29004 | + * it under the terms of the GNU General Public License as published by | |
29005 | + * the Free Software Foundation; either version 2 of the License, or | |
29006 | + * (at your option) any later version. | |
29007 | + * | |
29008 | + * This program is distributed in the hope that it will be useful, | |
29009 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
29010 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
29011 | + * GNU General Public License for more details. | |
29012 | + * | |
29013 | + * You should have received a copy of the GNU General Public License | |
29014 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
29015 | + */ | |
29016 | + | |
29017 | +// #define DEBUG // error path messages, extra info | |
29018 | +// #define VERBOSE // more; success messages | |
29019 | + | |
29020 | +#include <linux/module.h> | |
29021 | +#include <linux/netdevice.h> | |
29022 | +#include <linux/ethtool.h> | |
29023 | +#include <linux/workqueue.h> | |
29024 | +#include <linux/mii.h> | |
29025 | +#include <linux/crc32.h> | |
29026 | +#include <linux/usb.h> | |
29027 | +#include <linux/usb/cdc.h> | |
29028 | +#include <linux/usb/usbnet.h> | |
29029 | + | |
29030 | + | |
29031 | +/* | |
29032 | + * All known Zaurii lie about their standards conformance. At least | |
29033 | + * the earliest SA-1100 models lie by saying they support CDC Ethernet. | |
29034 | + * Some later models (especially PXA-25x and PXA-27x based ones) lie | |
29035 | + * and say they support CDC MDLM (for access to cell phone modems). | |
29036 | + * | |
29037 | + * There are non-Zaurus products that use these same protocols too. | |
29038 | + * | |
29039 | + * The annoying thing is that at the same time Sharp was developing | |
29040 | + * that annoying standards-breaking software, the Linux community had | |
29041 | + * a simple "CDC Subset" working reliably on the same SA-1100 hardware. | |
29042 | + * That is, the same functionality but not violating standards. | |
29043 | + * | |
29044 | + * The CDC Ethernet nonconformance points are troublesome to hosts | |
29045 | + * with a true CDC Ethernet implementation: | |
29046 | + * - Framing appends a CRC, which the spec says drivers "must not" do; | |
29047 | + * - Transfers data in altsetting zero, instead of altsetting 1; | |
29048 | + * - All these peripherals use the same ethernet address. | |
29049 | + * | |
29050 | + * The CDC MDLM nonconformance is less immediately troublesome, since all | |
29051 | + * MDLM implementations are quasi-proprietary anyway. | |
29052 | + */ | |
29053 | + | |
29054 | +static struct sk_buff * | |
29055 | +zaurus_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | |
29056 | +{ | |
29057 | + int padlen; | |
29058 | + struct sk_buff *skb2; | |
29059 | + | |
29060 | + padlen = 2; | |
29061 | + if (!skb_cloned(skb)) { | |
29062 | + int tailroom = skb_tailroom(skb); | |
29063 | + if ((padlen + 4) <= tailroom) | |
29064 | + goto done; | |
29065 | + } | |
29066 | + skb2 = skb_copy_expand(skb, 0, 4 + padlen, flags); | |
29067 | + dev_kfree_skb_any(skb); | |
29068 | + skb = skb2; | |
29069 | + if (skb) { | |
29070 | + u32 fcs; | |
29071 | +done: | |
29072 | + fcs = crc32_le(~0, skb->data, skb->len); | |
29073 | + fcs = ~fcs; | |
29074 | + | |
29075 | + *skb_put (skb, 1) = fcs & 0xff; | |
29076 | + *skb_put (skb, 1) = (fcs>> 8) & 0xff; | |
29077 | + *skb_put (skb, 1) = (fcs>>16) & 0xff; | |
29078 | + *skb_put (skb, 1) = (fcs>>24) & 0xff; | |
29079 | + } | |
29080 | + return skb; | |
29081 | +} | |
29082 | + | |
29083 | +static int zaurus_bind(struct usbnet *dev, struct usb_interface *intf) | |
29084 | +{ | |
29085 | + /* Belcarra's funky framing has other options; mostly | |
29086 | + * TRAILERS (!) with 4 bytes CRC, and maybe 2 pad bytes. | |
29087 | + */ | |
29088 | + dev->net->hard_header_len += 6; | |
29089 | + dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu; | |
29090 | + return usbnet_generic_cdc_bind(dev, intf); | |
29091 | +} | |
29092 | + | |
29093 | +/* PDA style devices are always connected if present */ | |
29094 | +static int always_connected (struct usbnet *dev) | |
29095 | +{ | |
29096 | + return 0; | |
29097 | +} | |
29098 | + | |
29099 | +static const struct driver_info zaurus_sl5x00_info = { | |
29100 | + .description = "Sharp Zaurus SL-5x00", | |
29101 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, | |
29102 | + .check_connect = always_connected, | |
29103 | + .bind = zaurus_bind, | |
29104 | + .unbind = usbnet_cdc_unbind, | |
29105 | + .tx_fixup = zaurus_tx_fixup, | |
29106 | +}; | |
29107 | +#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) | |
29108 | + | |
29109 | +static const struct driver_info zaurus_pxa_info = { | |
29110 | + .description = "Sharp Zaurus, PXA-2xx based", | |
29111 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, | |
29112 | + .check_connect = always_connected, | |
29113 | + .bind = zaurus_bind, | |
29114 | + .unbind = usbnet_cdc_unbind, | |
29115 | + .tx_fixup = zaurus_tx_fixup, | |
29116 | +}; | |
29117 | +#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) | |
29118 | + | |
29119 | +static const struct driver_info olympus_mxl_info = { | |
29120 | + .description = "Olympus R1000", | |
29121 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, | |
29122 | + .check_connect = always_connected, | |
29123 | + .bind = zaurus_bind, | |
29124 | + .unbind = usbnet_cdc_unbind, | |
29125 | + .tx_fixup = zaurus_tx_fixup, | |
29126 | +}; | |
29127 | +#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) | |
29128 | + | |
29129 | + | |
29130 | +/* Some more recent products using Lineo/Belcarra code will wrongly claim | |
29131 | + * CDC MDLM conformance. They aren't conformant: data endpoints live | |
29132 | + * in the control interface, there's no data interface, and it's not used | |
29133 | + * to talk to a cell phone radio. But at least we can detect these two | |
29134 | + * pseudo-classes, rather than growing this product list with entries for | |
29135 | + * each new nonconformant product (sigh). | |
29136 | + */ | |
29137 | +static const u8 safe_guid[16] = { | |
29138 | + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, | |
29139 | + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, | |
29140 | +}; | |
29141 | +static const u8 blan_guid[16] = { | |
29142 | + 0x74, 0xf0, 0x3d, 0xbd, 0x1e, 0xc1, 0x44, 0x70, | |
29143 | + 0xa3, 0x67, 0x71, 0x34, 0xc9, 0xf5, 0x54, 0x37, | |
29144 | +}; | |
29145 | + | |
29146 | +static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) | |
29147 | +{ | |
29148 | + u8 *buf = intf->cur_altsetting->extra; | |
29149 | + int len = intf->cur_altsetting->extralen; | |
29150 | + struct usb_cdc_mdlm_desc *desc = NULL; | |
29151 | + struct usb_cdc_mdlm_detail_desc *detail = NULL; | |
29152 | + | |
29153 | + while (len > 3) { | |
29154 | + if (buf [1] != USB_DT_CS_INTERFACE) | |
29155 | + goto next_desc; | |
29156 | + | |
29157 | + /* use bDescriptorSubType, and just verify that we get a | |
29158 | + * "BLAN" (or "SAFE") descriptor. | |
29159 | + */ | |
29160 | + switch (buf [2]) { | |
29161 | + case USB_CDC_MDLM_TYPE: | |
29162 | + if (desc) { | |
29163 | + dev_dbg(&intf->dev, "extra MDLM\n"); | |
29164 | + goto bad_desc; | |
29165 | + } | |
29166 | + desc = (void *) buf; | |
29167 | + if (desc->bLength != sizeof *desc) { | |
29168 | + dev_dbg(&intf->dev, "MDLM len %u\n", | |
29169 | + desc->bLength); | |
29170 | + goto bad_desc; | |
29171 | + } | |
29172 | + /* expect bcdVersion 1.0, ignore */ | |
29173 | + if (memcmp(&desc->bGUID, blan_guid, 16) && | |
29174 | + memcmp(&desc->bGUID, safe_guid, 16)) { | |
29175 | + /* hey, this one might _really_ be MDLM! */ | |
29176 | + dev_dbg(&intf->dev, "MDLM guid\n"); | |
29177 | + goto bad_desc; | |
29178 | + } | |
29179 | + break; | |
29180 | + case USB_CDC_MDLM_DETAIL_TYPE: | |
29181 | + if (detail) { | |
29182 | + dev_dbg(&intf->dev, "extra MDLM detail\n"); | |
29183 | + goto bad_desc; | |
29184 | + } | |
29185 | + detail = (void *) buf; | |
29186 | + switch (detail->bGuidDescriptorType) { | |
29187 | + case 0: /* "SAFE" */ | |
29188 | + if (detail->bLength != (sizeof *detail + 2)) | |
29189 | + goto bad_detail; | |
29190 | + break; | |
29191 | + case 1: /* "BLAN" */ | |
29192 | + if (detail->bLength != (sizeof *detail + 3)) | |
29193 | + goto bad_detail; | |
29194 | + break; | |
29195 | + default: | |
29196 | + goto bad_detail; | |
29197 | + } | |
29198 | + | |
29199 | + /* assuming we either noticed BLAN already, or will | |
29200 | + * find it soon, there are some data bytes here: | |
29201 | + * - bmNetworkCapabilities (unused) | |
29202 | + * - bmDataCapabilities (bits, see below) | |
29203 | + * - bPad (ignored, for PADAFTER -- BLAN-only) | |
29204 | + * bits are: | |
29205 | + * - 0x01 -- Zaurus framing (add CRC) | |
29206 | + * - 0x02 -- PADBEFORE (CRC includes some padding) | |
29207 | + * - 0x04 -- PADAFTER (some padding after CRC) | |
29208 | + * - 0x08 -- "fermat" packet mangling (for hw bugs) | |
29209 | + * the PADBEFORE appears not to matter; we interop | |
29210 | + * with devices that use it and those that don't. | |
29211 | + */ | |
29212 | + if ((detail->bDetailData[1] & ~0x02) != 0x01) { | |
29213 | + /* bmDataCapabilities == 0 would be fine too, | |
29214 | + * but framing is minidriver-coupled for now. | |
29215 | + */ | |
29216 | +bad_detail: | |
29217 | + dev_dbg(&intf->dev, | |
29218 | + "bad MDLM detail, %d %d %d\n", | |
29219 | + detail->bLength, | |
29220 | + detail->bDetailData[0], | |
29221 | + detail->bDetailData[2]); | |
29222 | + goto bad_desc; | |
29223 | + } | |
29224 | + | |
29225 | + /* same extra framing as for non-BLAN mode */ | |
29226 | + dev->net->hard_header_len += 6; | |
29227 | + dev->rx_urb_size = dev->net->hard_header_len | |
29228 | + + dev->net->mtu; | |
29229 | + break; | |
29230 | + } | |
29231 | +next_desc: | |
29232 | + len -= buf [0]; /* bLength */ | |
29233 | + buf += buf [0]; | |
29234 | + } | |
29235 | + | |
29236 | + if (!desc || !detail) { | |
29237 | + dev_dbg(&intf->dev, "missing cdc mdlm %s%sdescriptor\n", | |
29238 | + desc ? "" : "func ", | |
29239 | + detail ? "" : "detail "); | |
29240 | + goto bad_desc; | |
29241 | + } | |
29242 | + | |
29243 | + /* There's probably a CDC Ethernet descriptor there, but we can't | |
29244 | + * rely on the Ethernet address it provides since not all vendors | |
29245 | + * bother to make it unique. Likewise there's no point in tracking | |
29246 | + * of the CDC event notifications. | |
29247 | + */ | |
29248 | + return usbnet_get_endpoints(dev, intf); | |
29249 | + | |
29250 | +bad_desc: | |
29251 | + dev_info(&dev->udev->dev, "unsupported MDLM descriptors\n"); | |
29252 | + return -ENODEV; | |
29253 | +} | |
29254 | + | |
29255 | +static const struct driver_info bogus_mdlm_info = { | |
29256 | + .description = "pseudo-MDLM (BLAN) device", | |
29257 | + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, | |
29258 | + .check_connect = always_connected, | |
29259 | + .tx_fixup = zaurus_tx_fixup, | |
29260 | + .bind = blan_mdlm_bind, | |
29261 | +}; | |
29262 | + | |
29263 | +static const struct usb_device_id products [] = { | |
29264 | +#define ZAURUS_MASTER_INTERFACE \ | |
29265 | + .bInterfaceClass = USB_CLASS_COMM, \ | |
29266 | + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ | |
29267 | + .bInterfaceProtocol = USB_CDC_PROTO_NONE | |
29268 | + | |
29269 | +/* SA-1100 based Sharp Zaurus ("collie"), or compatible. */ | |
29270 | +{ | |
29271 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29272 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29273 | + .idVendor = 0x04DD, | |
29274 | + .idProduct = 0x8004, | |
29275 | + ZAURUS_MASTER_INTERFACE, | |
29276 | + .driver_info = ZAURUS_STRONGARM_INFO, | |
29277 | +}, | |
29278 | + | |
29279 | +/* PXA-2xx based models are also lying-about-cdc. If you add any | |
29280 | + * more devices that claim to be CDC Ethernet, make sure they get | |
29281 | + * added to the blacklist in cdc_ether too. | |
29282 | + * | |
29283 | + * NOTE: OpenZaurus versions with 2.6 kernels won't use these entries, | |
29284 | + * unlike the older ones with 2.4 "embedix" kernels. | |
29285 | + */ | |
29286 | +{ | |
29287 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29288 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29289 | + .idVendor = 0x04DD, | |
29290 | + .idProduct = 0x8005, /* A-300 */ | |
29291 | + ZAURUS_MASTER_INTERFACE, | |
29292 | + .driver_info = ZAURUS_PXA_INFO, | |
29293 | +}, { | |
29294 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29295 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29296 | + .idVendor = 0x04DD, | |
29297 | + .idProduct = 0x8006, /* B-500/SL-5600 */ | |
29298 | + ZAURUS_MASTER_INTERFACE, | |
29299 | + .driver_info = ZAURUS_PXA_INFO, | |
29300 | +}, { | |
29301 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29302 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29303 | + .idVendor = 0x04DD, | |
29304 | + .idProduct = 0x8007, /* C-700 */ | |
29305 | + ZAURUS_MASTER_INTERFACE, | |
29306 | + .driver_info = ZAURUS_PXA_INFO, | |
29307 | +}, { | |
29308 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29309 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29310 | + .idVendor = 0x04DD, | |
29311 | + .idProduct = 0x9031, /* C-750 C-760 */ | |
29312 | + ZAURUS_MASTER_INTERFACE, | |
29313 | + .driver_info = ZAURUS_PXA_INFO, | |
29314 | +}, { | |
29315 | + /* C-750/C-760/C-860/SL-C3000 PDA in MDLM mode */ | |
29316 | + USB_DEVICE_AND_INTERFACE_INFO(0x04DD, 0x9031, USB_CLASS_COMM, | |
29317 | + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), | |
29318 | + .driver_info = (unsigned long) &bogus_mdlm_info, | |
29319 | +}, { | |
29320 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29321 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29322 | + .idVendor = 0x04DD, | |
29323 | + .idProduct = 0x9032, /* SL-6000 */ | |
29324 | + ZAURUS_MASTER_INTERFACE, | |
29325 | + .driver_info = ZAURUS_PXA_INFO, | |
29326 | +}, { | |
29327 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29328 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29329 | + .idVendor = 0x04DD, | |
29330 | + /* reported with some C860 units */ | |
29331 | + .idProduct = 0x9050, /* C-860 */ | |
29332 | + ZAURUS_MASTER_INTERFACE, | |
29333 | + .driver_info = ZAURUS_PXA_INFO, | |
29334 | +}, | |
29335 | +{ | |
29336 | + /* Motorola Rokr E6 */ | |
29337 | + USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6027, USB_CLASS_COMM, | |
29338 | + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), | |
29339 | + .driver_info = (unsigned long) &bogus_mdlm_info, | |
29340 | +}, { | |
29341 | + /* Motorola MOTOMAGX phones */ | |
29342 | + USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM, | |
29343 | + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), | |
29344 | + .driver_info = (unsigned long) &bogus_mdlm_info, | |
29345 | +}, | |
29346 | + | |
29347 | +/* Olympus has some models with a Zaurus-compatible option. | |
29348 | + * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) | |
29349 | + */ | |
29350 | +{ | |
29351 | + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | |
29352 | + | USB_DEVICE_ID_MATCH_DEVICE, | |
29353 | + .idVendor = 0x07B4, | |
29354 | + .idProduct = 0x0F02, /* R-1000 */ | |
29355 | + ZAURUS_MASTER_INTERFACE, | |
29356 | + .driver_info = OLYMPUS_MXL_INFO, | |
29357 | +}, | |
29358 | + | |
29359 | +/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */ | |
29360 | +{ | |
29361 | + USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM, | |
29362 | + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), | |
29363 | + .driver_info = (unsigned long) &bogus_mdlm_info, | |
29364 | +}, | |
29365 | + { }, // END | |
29366 | +}; | |
29367 | +MODULE_DEVICE_TABLE(usb, products); | |
29368 | + | |
29369 | +static struct usb_driver zaurus_driver = { | |
29370 | + .name = "zaurus", | |
29371 | + .id_table = products, | |
29372 | + .probe = usbnet_probe, | |
29373 | + .disconnect = usbnet_disconnect, | |
29374 | + .suspend = usbnet_suspend, | |
29375 | + .resume = usbnet_resume, | |
29376 | + .disable_hub_initiated_lpm = 1, | |
29377 | +}; | |
29378 | + | |
29379 | +module_usb_driver(zaurus_driver); | |
29380 | + | |
29381 | +MODULE_AUTHOR("Pavel Machek, David Brownell"); | |
29382 | +MODULE_DESCRIPTION("Sharp Zaurus PDA, and compatible products"); | |
29383 | +MODULE_LICENSE("GPL"); |