diff options
Diffstat (limited to 'drivers/net/usb')
28 files changed, 2810 insertions, 367 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index d7b7018a1de1..84d4608153c9 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig | |||
@@ -196,6 +196,25 @@ config USB_NET_CDC_EEM | |||
196 | IEEE 802 "local assignment" bit is set in the address, a "usbX" | 196 | IEEE 802 "local assignment" bit is set in the address, a "usbX" |
197 | name is used instead. | 197 | name is used instead. |
198 | 198 | ||
199 | config USB_NET_CDC_NCM | ||
200 | tristate "CDC NCM support" | ||
201 | depends on USB_USBNET | ||
202 | default y | ||
203 | help | ||
204 | This driver provides support for CDC NCM (Network Control Model | ||
205 | Device USB Class Specification). The CDC NCM specification is | ||
206 | available from <http://www.usb.org/>. | ||
207 | |||
208 | Say "y" to link the driver statically, or "m" to build a | ||
209 | dynamically linked module. | ||
210 | |||
211 | This driver should work with at least the following devices: | ||
212 | * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design) | ||
213 | * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design) | ||
214 | * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design) | ||
215 | * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design) | ||
216 | * Ericsson F5521gw Mobile Broadband Module | ||
217 | |||
199 | config USB_NET_DM9601 | 218 | config USB_NET_DM9601 |
200 | tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" | 219 | tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" |
201 | depends on USB_USBNET | 220 | depends on USB_USBNET |
@@ -239,7 +258,7 @@ config USB_NET_NET1080 | |||
239 | optionally with LEDs that indicate traffic | 258 | optionally with LEDs that indicate traffic |
240 | 259 | ||
241 | config USB_NET_PLUSB | 260 | config USB_NET_PLUSB |
242 | tristate "Prolific PL-2301/2302 based cables" | 261 | tristate "Prolific PL-2301/2302/25A1 based cables" |
243 | # if the handshake/init/reset problems, from original 'plusb', | 262 | # if the handshake/init/reset problems, from original 'plusb', |
244 | # are ever resolved ... then remove "experimental" | 263 | # are ever resolved ... then remove "experimental" |
245 | depends on USB_USBNET && EXPERIMENTAL | 264 | depends on USB_USBNET && EXPERIMENTAL |
@@ -358,6 +377,24 @@ config USB_NET_ZAURUS | |||
358 | really need this non-conformant variant of CDC Ethernet (or in | 377 | really need this non-conformant variant of CDC Ethernet (or in |
359 | some cases CDC MDLM) protocol, not "g_ether". | 378 | some cases CDC MDLM) protocol, not "g_ether". |
360 | 379 | ||
380 | config USB_NET_CX82310_ETH | ||
381 | tristate "Conexant CX82310 USB ethernet port" | ||
382 | depends on USB_USBNET | ||
383 | help | ||
384 | Choose this option if you're using a Conexant CX82310-based ADSL | ||
385 | router with USB ethernet port. This driver is for routers only, | ||
386 | it will not work with ADSL modems (use cxacru driver instead). | ||
387 | |||
388 | config USB_NET_KALMIA | ||
389 | tristate "Samsung Kalmia based LTE USB modem" | ||
390 | depends on USB_USBNET | ||
391 | help | ||
392 | Choose this option if you have a Samsung Kalmia based USB modem | ||
393 | as Samsung GT-B3730. | ||
394 | |||
395 | To compile this driver as a module, choose M here: the | ||
396 | module will be called kalmia. | ||
397 | |||
361 | config USB_HSO | 398 | config USB_HSO |
362 | tristate "Option USB High Speed Mobile Devices" | 399 | tristate "Option USB High Speed Mobile Devices" |
363 | depends on USB && RFKILL | 400 | depends on USB && RFKILL |
@@ -406,4 +443,19 @@ config USB_SIERRA_NET | |||
406 | To compile this driver as a module, choose M here: the | 443 | To compile this driver as a module, choose M here: the |
407 | module will be called sierra_net. | 444 | module will be called sierra_net. |
408 | 445 | ||
446 | config USB_VL600 | ||
447 | tristate "LG VL600 modem dongle" | ||
448 | depends on USB_NET_CDCETHER | ||
449 | select USB_ACM | ||
450 | help | ||
451 | Select this if you want to use an LG Electronics 4G/LTE usb modem | ||
452 | called VL600. This driver only handles the ethernet | ||
453 | interface exposed by the modem firmware. To establish a connection | ||
454 | you will first need a userspace program that sends the right | ||
455 | command to the modem through its CDC ACM port, and most | ||
456 | likely also a DHCP client. See this thread about using the | ||
457 | 4G modem from Verizon: | ||
458 | |||
459 | http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 | ||
460 | |||
409 | endmenu | 461 | endmenu |
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index b13a279663ba..c203fa21f6b1 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile | |||
@@ -23,6 +23,10 @@ obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o | |||
23 | obj-$(CONFIG_USB_USBNET) += usbnet.o | 23 | obj-$(CONFIG_USB_USBNET) += usbnet.o |
24 | obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o | 24 | obj-$(CONFIG_USB_NET_INT51X1) += int51x1.o |
25 | obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o | 25 | obj-$(CONFIG_USB_CDC_PHONET) += cdc-phonet.o |
26 | obj-$(CONFIG_USB_NET_KALMIA) += kalmia.o | ||
26 | obj-$(CONFIG_USB_IPHETH) += ipheth.o | 27 | obj-$(CONFIG_USB_IPHETH) += ipheth.o |
27 | obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o | 28 | obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o |
29 | obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o | ||
30 | obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o | ||
31 | obj-$(CONFIG_USB_VL600) += lg-vl600.o | ||
28 | 32 | ||
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index aea4645be7f6..6998aa6b7bb7 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c | |||
@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net) | |||
847 | static int ax88172_link_reset(struct usbnet *dev) | 847 | static int ax88172_link_reset(struct usbnet *dev) |
848 | { | 848 | { |
849 | u8 mode; | 849 | u8 mode; |
850 | struct ethtool_cmd ecmd; | 850 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
851 | 851 | ||
852 | mii_check_media(&dev->mii, 1, 1); | 852 | mii_check_media(&dev->mii, 1, 1); |
853 | mii_ethtool_gset(&dev->mii, &ecmd); | 853 | mii_ethtool_gset(&dev->mii, &ecmd); |
@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev) | |||
856 | if (ecmd.duplex != DUPLEX_FULL) | 856 | if (ecmd.duplex != DUPLEX_FULL) |
857 | mode |= ~AX88172_MEDIUM_FD; | 857 | mode |= ~AX88172_MEDIUM_FD; |
858 | 858 | ||
859 | netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", | 859 | netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", |
860 | ecmd.speed, ecmd.duplex, mode); | 860 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); |
861 | 861 | ||
862 | asix_write_medium_mode(dev, mode); | 862 | asix_write_medium_mode(dev, mode); |
863 | 863 | ||
@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = { | |||
947 | static int ax88772_link_reset(struct usbnet *dev) | 947 | static int ax88772_link_reset(struct usbnet *dev) |
948 | { | 948 | { |
949 | u16 mode; | 949 | u16 mode; |
950 | struct ethtool_cmd ecmd; | 950 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
951 | 951 | ||
952 | mii_check_media(&dev->mii, 1, 1); | 952 | mii_check_media(&dev->mii, 1, 1); |
953 | mii_ethtool_gset(&dev->mii, &ecmd); | 953 | mii_ethtool_gset(&dev->mii, &ecmd); |
954 | mode = AX88772_MEDIUM_DEFAULT; | 954 | mode = AX88772_MEDIUM_DEFAULT; |
955 | 955 | ||
956 | if (ecmd.speed != SPEED_100) | 956 | if (ethtool_cmd_speed(&ecmd) != SPEED_100) |
957 | mode &= ~AX_MEDIUM_PS; | 957 | mode &= ~AX_MEDIUM_PS; |
958 | 958 | ||
959 | if (ecmd.duplex != DUPLEX_FULL) | 959 | if (ecmd.duplex != DUPLEX_FULL) |
960 | mode &= ~AX_MEDIUM_FD; | 960 | mode &= ~AX_MEDIUM_FD; |
961 | 961 | ||
962 | netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", | 962 | netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", |
963 | ecmd.speed, ecmd.duplex, mode); | 963 | ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); |
964 | 964 | ||
965 | asix_write_medium_mode(dev, mode); | 965 | asix_write_medium_mode(dev, mode); |
966 | 966 | ||
@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed) | |||
1173 | static int ax88178_link_reset(struct usbnet *dev) | 1173 | static int ax88178_link_reset(struct usbnet *dev) |
1174 | { | 1174 | { |
1175 | u16 mode; | 1175 | u16 mode; |
1176 | struct ethtool_cmd ecmd; | 1176 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
1177 | struct asix_data *data = (struct asix_data *)&dev->data; | 1177 | struct asix_data *data = (struct asix_data *)&dev->data; |
1178 | u32 speed; | ||
1178 | 1179 | ||
1179 | netdev_dbg(dev->net, "ax88178_link_reset()\n"); | 1180 | netdev_dbg(dev->net, "ax88178_link_reset()\n"); |
1180 | 1181 | ||
1181 | mii_check_media(&dev->mii, 1, 1); | 1182 | mii_check_media(&dev->mii, 1, 1); |
1182 | mii_ethtool_gset(&dev->mii, &ecmd); | 1183 | mii_ethtool_gset(&dev->mii, &ecmd); |
1183 | mode = AX88178_MEDIUM_DEFAULT; | 1184 | mode = AX88178_MEDIUM_DEFAULT; |
1185 | speed = ethtool_cmd_speed(&ecmd); | ||
1184 | 1186 | ||
1185 | if (ecmd.speed == SPEED_1000) | 1187 | if (speed == SPEED_1000) |
1186 | mode |= AX_MEDIUM_GM; | 1188 | mode |= AX_MEDIUM_GM; |
1187 | else if (ecmd.speed == SPEED_100) | 1189 | else if (speed == SPEED_100) |
1188 | mode |= AX_MEDIUM_PS; | 1190 | mode |= AX_MEDIUM_PS; |
1189 | else | 1191 | else |
1190 | mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); | 1192 | mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); |
@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev) | |||
1196 | else | 1198 | else |
1197 | mode &= ~AX_MEDIUM_FD; | 1199 | mode &= ~AX_MEDIUM_FD; |
1198 | 1200 | ||
1199 | netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n", | 1201 | netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", |
1200 | ecmd.speed, ecmd.duplex, mode); | 1202 | speed, ecmd.duplex, mode); |
1201 | 1203 | ||
1202 | asix_write_medium_mode(dev, mode); | 1204 | asix_write_medium_mode(dev, mode); |
1203 | 1205 | ||
1204 | if (data->phymode == PHY_MODE_MARVELL && data->ledmode) | 1206 | if (data->phymode == PHY_MODE_MARVELL && data->ledmode) |
1205 | marvell_led_status(dev, ecmd.speed); | 1207 | marvell_led_status(dev, speed); |
1206 | 1208 | ||
1207 | return 0; | 1209 | return 0; |
1208 | } | 1210 | } |
@@ -1508,6 +1510,10 @@ static const struct usb_device_id products [] = { | |||
1508 | USB_DEVICE (0x0b95, 0x1780), | 1510 | USB_DEVICE (0x0b95, 0x1780), |
1509 | .driver_info = (unsigned long) &ax88178_info, | 1511 | .driver_info = (unsigned long) &ax88178_info, |
1510 | }, { | 1512 | }, { |
1513 | // Logitec LAN-GTJ/U2A | ||
1514 | USB_DEVICE (0x0789, 0x0160), | ||
1515 | .driver_info = (unsigned long) &ax88178_info, | ||
1516 | }, { | ||
1511 | // Linksys USB200M Rev 2 | 1517 | // Linksys USB200M Rev 2 |
1512 | USB_DEVICE (0x13b1, 0x0018), | 1518 | USB_DEVICE (0x13b1, 0x0018), |
1513 | .driver_info = (unsigned long) &ax88772_info, | 1519 | .driver_info = (unsigned long) &ax88772_info, |
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 97687d335903..8056f8a27c6a 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c | |||
@@ -495,7 +495,7 @@ static void catc_ctrl_run(struct catc *catc) | |||
495 | if (!q->dir && q->buf && q->len) | 495 | if (!q->dir && q->buf && q->len) |
496 | memcpy(catc->ctrl_buf, q->buf, q->len); | 496 | memcpy(catc->ctrl_buf, q->buf, q->len); |
497 | 497 | ||
498 | if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL))) | 498 | if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC))) |
499 | err("submit(ctrl_urb) status %d", status); | 499 | err("submit(ctrl_urb) status %d", status); |
500 | } | 500 | } |
501 | 501 | ||
@@ -686,7 +686,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
686 | 686 | ||
687 | cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; | 687 | cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP; |
688 | cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; | 688 | cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP; |
689 | cmd->speed = SPEED_10; | 689 | ethtool_cmd_speed_set(cmd, SPEED_10); |
690 | cmd->duplex = DUPLEX_HALF; | 690 | cmd->duplex = DUPLEX_HALF; |
691 | cmd->port = PORT_TP; | 691 | cmd->port = PORT_TP; |
692 | cmd->phy_address = 0; | 692 | cmd->phy_address = 0; |
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 109751bad3bb..f967913e11bc 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c | |||
@@ -328,13 +328,13 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
328 | { | 328 | { |
329 | static const char ifname[] = "usbpn%d"; | 329 | static const char ifname[] = "usbpn%d"; |
330 | const struct usb_cdc_union_desc *union_header = NULL; | 330 | const struct usb_cdc_union_desc *union_header = NULL; |
331 | const struct usb_cdc_header_desc *phonet_header = NULL; | ||
332 | const struct usb_host_interface *data_desc; | 331 | const struct usb_host_interface *data_desc; |
333 | struct usb_interface *data_intf; | 332 | struct usb_interface *data_intf; |
334 | struct usb_device *usbdev = interface_to_usbdev(intf); | 333 | struct usb_device *usbdev = interface_to_usbdev(intf); |
335 | struct net_device *dev; | 334 | struct net_device *dev; |
336 | struct usbpn_dev *pnd; | 335 | struct usbpn_dev *pnd; |
337 | u8 *data; | 336 | u8 *data; |
337 | int phonet = 0; | ||
338 | int len, err; | 338 | int len, err; |
339 | 339 | ||
340 | data = intf->altsetting->extra; | 340 | data = intf->altsetting->extra; |
@@ -355,10 +355,7 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
355 | (struct usb_cdc_union_desc *)data; | 355 | (struct usb_cdc_union_desc *)data; |
356 | break; | 356 | break; |
357 | case 0xAB: | 357 | case 0xAB: |
358 | if (phonet_header || dlen < 5) | 358 | phonet = 1; |
359 | break; | ||
360 | phonet_header = | ||
361 | (struct usb_cdc_header_desc *)data; | ||
362 | break; | 359 | break; |
363 | } | 360 | } |
364 | } | 361 | } |
@@ -366,7 +363,7 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
366 | len -= dlen; | 363 | len -= dlen; |
367 | } | 364 | } |
368 | 365 | ||
369 | if (!union_header || !phonet_header) | 366 | if (!union_header || !phonet) |
370 | return -EINVAL; | 367 | return -EINVAL; |
371 | 368 | ||
372 | data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0); | 369 | data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0); |
@@ -392,7 +389,6 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
392 | 389 | ||
393 | pnd = netdev_priv(dev); | 390 | pnd = netdev_priv(dev); |
394 | SET_NETDEV_DEV(dev, &intf->dev); | 391 | SET_NETDEV_DEV(dev, &intf->dev); |
395 | netif_stop_queue(dev); | ||
396 | 392 | ||
397 | pnd->dev = dev; | 393 | pnd->dev = dev; |
398 | pnd->usb = usb_get_dev(usbdev); | 394 | pnd->usb = usb_get_dev(usbdev); |
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 5f3b97668e63..882f53f708df 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c | |||
@@ -190,7 +190,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
190 | 190 | ||
191 | /* | 191 | /* |
192 | * EEM packet header format: | 192 | * EEM packet header format: |
193 | * b0..14: EEM type dependant (Data or Command) | 193 | * b0..14: EEM type dependent (Data or Command) |
194 | * b15: bmType | 194 | * b15: bmType |
195 | */ | 195 | */ |
196 | header = get_unaligned_le16(skb->data); | 196 | header = get_unaligned_le16(skb->data); |
@@ -340,7 +340,7 @@ next: | |||
340 | 340 | ||
341 | static const struct driver_info eem_info = { | 341 | static const struct driver_info eem_info = { |
342 | .description = "CDC EEM Device", | 342 | .description = "CDC EEM Device", |
343 | .flags = FLAG_ETHER, | 343 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT, |
344 | .bind = eem_bind, | 344 | .bind = eem_bind, |
345 | .rx_fixup = eem_rx_fixup, | 345 | .rx_fixup = eem_rx_fixup, |
346 | .tx_fixup = eem_tx_fixup, | 346 | .tx_fixup = eem_tx_fixup, |
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index b3fe0de40469..c924ea2bce07 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c | |||
@@ -99,9 +99,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) | |||
99 | */ | 99 | */ |
100 | buf = dev->udev->actconfig->extra; | 100 | buf = dev->udev->actconfig->extra; |
101 | len = dev->udev->actconfig->extralen; | 101 | len = dev->udev->actconfig->extralen; |
102 | if (len) | 102 | dev_dbg(&intf->dev, "CDC descriptors on config\n"); |
103 | dev_dbg(&intf->dev, | ||
104 | "CDC descriptors on config\n"); | ||
105 | } | 103 | } |
106 | 104 | ||
107 | /* Maybe CDC descriptors are after the endpoint? This bug has | 105 | /* Maybe CDC descriptors are after the endpoint? This bug has |
@@ -380,7 +378,7 @@ static void dumpspeed(struct usbnet *dev, __le32 *speeds) | |||
380 | __le32_to_cpu(speeds[1]) / 1000); | 378 | __le32_to_cpu(speeds[1]) / 1000); |
381 | } | 379 | } |
382 | 380 | ||
383 | static void cdc_status(struct usbnet *dev, struct urb *urb) | 381 | void usbnet_cdc_status(struct usbnet *dev, struct urb *urb) |
384 | { | 382 | { |
385 | struct usb_cdc_notification *event; | 383 | struct usb_cdc_notification *event; |
386 | 384 | ||
@@ -420,8 +418,9 @@ static void cdc_status(struct usbnet *dev, struct urb *urb) | |||
420 | break; | 418 | break; |
421 | } | 419 | } |
422 | } | 420 | } |
421 | EXPORT_SYMBOL_GPL(usbnet_cdc_status); | ||
423 | 422 | ||
424 | static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) | 423 | int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf) |
425 | { | 424 | { |
426 | int status; | 425 | int status; |
427 | struct cdc_state *info = (void *) &dev->data; | 426 | struct cdc_state *info = (void *) &dev->data; |
@@ -443,6 +442,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) | |||
443 | */ | 442 | */ |
444 | return 0; | 443 | return 0; |
445 | } | 444 | } |
445 | EXPORT_SYMBOL_GPL(usbnet_cdc_bind); | ||
446 | 446 | ||
447 | static int cdc_manage_power(struct usbnet *dev, int on) | 447 | static int cdc_manage_power(struct usbnet *dev, int on) |
448 | { | 448 | { |
@@ -452,25 +452,26 @@ static int cdc_manage_power(struct usbnet *dev, int on) | |||
452 | 452 | ||
453 | static const struct driver_info cdc_info = { | 453 | static const struct driver_info cdc_info = { |
454 | .description = "CDC Ethernet Device", | 454 | .description = "CDC Ethernet Device", |
455 | .flags = FLAG_ETHER, | 455 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT, |
456 | // .check_connect = cdc_check_connect, | 456 | // .check_connect = cdc_check_connect, |
457 | .bind = cdc_bind, | 457 | .bind = usbnet_cdc_bind, |
458 | .unbind = usbnet_cdc_unbind, | 458 | .unbind = usbnet_cdc_unbind, |
459 | .status = cdc_status, | 459 | .status = usbnet_cdc_status, |
460 | .manage_power = cdc_manage_power, | 460 | .manage_power = cdc_manage_power, |
461 | }; | 461 | }; |
462 | 462 | ||
463 | static const struct driver_info mbm_info = { | 463 | static const struct driver_info wwan_info = { |
464 | .description = "Mobile Broadband Network Device", | 464 | .description = "Mobile Broadband Network Device", |
465 | .flags = FLAG_WWAN, | 465 | .flags = FLAG_WWAN, |
466 | .bind = cdc_bind, | 466 | .bind = usbnet_cdc_bind, |
467 | .unbind = usbnet_cdc_unbind, | 467 | .unbind = usbnet_cdc_unbind, |
468 | .status = cdc_status, | 468 | .status = usbnet_cdc_status, |
469 | .manage_power = cdc_manage_power, | 469 | .manage_power = cdc_manage_power, |
470 | }; | 470 | }; |
471 | 471 | ||
472 | /*-------------------------------------------------------------------------*/ | 472 | /*-------------------------------------------------------------------------*/ |
473 | 473 | ||
474 | #define HUAWEI_VENDOR_ID 0x12D1 | ||
474 | 475 | ||
475 | static const struct usb_device_id products [] = { | 476 | static const struct usb_device_id products [] = { |
476 | /* | 477 | /* |
@@ -562,6 +563,13 @@ static const struct usb_device_id products [] = { | |||
562 | .driver_info = 0, | 563 | .driver_info = 0, |
563 | }, | 564 | }, |
564 | 565 | ||
566 | /* LG Electronics VL600 wants additional headers on every frame */ | ||
567 | { | ||
568 | USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, | ||
569 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
570 | .driver_info = (unsigned long)&wwan_info, | ||
571 | }, | ||
572 | |||
565 | /* | 573 | /* |
566 | * WHITELIST!!! | 574 | * WHITELIST!!! |
567 | * | 575 | * |
@@ -580,8 +588,17 @@ static const struct usb_device_id products [] = { | |||
580 | }, { | 588 | }, { |
581 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, | 589 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, |
582 | USB_CDC_PROTO_NONE), | 590 | USB_CDC_PROTO_NONE), |
583 | .driver_info = (unsigned long)&mbm_info, | 591 | .driver_info = (unsigned long)&wwan_info, |
584 | 592 | ||
593 | }, { | ||
594 | /* Various Huawei modems with a network port like the UMG1831 */ | ||
595 | .match_flags = USB_DEVICE_ID_MATCH_VENDOR | ||
596 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
597 | .idVendor = HUAWEI_VENDOR_ID, | ||
598 | .bInterfaceClass = USB_CLASS_COMM, | ||
599 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, | ||
600 | .bInterfaceProtocol = 255, | ||
601 | .driver_info = (unsigned long)&wwan_info, | ||
585 | }, | 602 | }, |
586 | { }, // END | 603 | { }, // END |
587 | }; | 604 | }; |
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c new file mode 100644 index 000000000000..f33ca6aa29e9 --- /dev/null +++ b/drivers/net/usb/cdc_ncm.c | |||
@@ -0,0 +1,1268 @@ | |||
1 | /* | ||
2 | * cdc_ncm.c | ||
3 | * | ||
4 | * Copyright (C) ST-Ericsson 2010-2011 | ||
5 | * Contact: Alexey Orishko <alexey.orishko@stericsson.com> | ||
6 | * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com> | ||
7 | * | ||
8 | * USB Host Driver for Network Control Model (NCM) | ||
9 | * http://www.usb.org/developers/devclass_docs/NCM10.zip | ||
10 | * | ||
11 | * The NCM encoding, decoding and initialization logic | ||
12 | * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h | ||
13 | * | ||
14 | * This software is available to you under a choice of one of two | ||
15 | * licenses. You may choose this file to be licensed under the terms | ||
16 | * of the GNU General Public License (GPL) Version 2 or the 2-clause | ||
17 | * BSD license listed below: | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions | ||
21 | * are met: | ||
22 | * 1. Redistributions of source code must retain the above copyright | ||
23 | * notice, this list of conditions and the following disclaimer. | ||
24 | * 2. Redistributions in binary form must reproduce the above copyright | ||
25 | * notice, this list of conditions and the following disclaimer in the | ||
26 | * documentation and/or other materials provided with the distribution. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
38 | * SUCH DAMAGE. | ||
39 | */ | ||
40 | |||
41 | #include <linux/module.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/netdevice.h> | ||
44 | #include <linux/ctype.h> | ||
45 | #include <linux/ethtool.h> | ||
46 | #include <linux/workqueue.h> | ||
47 | #include <linux/mii.h> | ||
48 | #include <linux/crc32.h> | ||
49 | #include <linux/usb.h> | ||
50 | #include <linux/version.h> | ||
51 | #include <linux/timer.h> | ||
52 | #include <linux/spinlock.h> | ||
53 | #include <linux/atomic.h> | ||
54 | #include <linux/usb/usbnet.h> | ||
55 | #include <linux/usb/cdc.h> | ||
56 | |||
57 | #define DRIVER_VERSION "01-June-2011" | ||
58 | |||
59 | /* CDC NCM subclass 3.2.1 */ | ||
60 | #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 | ||
61 | |||
62 | /* Maximum NTB length */ | ||
63 | #define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ | ||
64 | #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ | ||
65 | |||
66 | /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ | ||
67 | #define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */ | ||
68 | |||
69 | #define CDC_NCM_MIN_TX_PKT 512 /* bytes */ | ||
70 | |||
71 | /* Default value for MaxDatagramSize */ | ||
72 | #define CDC_NCM_MAX_DATAGRAM_SIZE 2048 /* bytes */ | ||
73 | |||
74 | /* | ||
75 | * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting | ||
76 | * the last NULL entry. Any additional datagrams in NTB would be discarded. | ||
77 | */ | ||
78 | #define CDC_NCM_DPT_DATAGRAMS_MAX 32 | ||
79 | |||
80 | /* Maximum amount of IN datagrams in NTB */ | ||
81 | #define CDC_NCM_DPT_DATAGRAMS_IN_MAX 0 /* unlimited */ | ||
82 | |||
83 | /* Restart the timer, if amount of datagrams is less than given value */ | ||
84 | #define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3 | ||
85 | |||
86 | /* The following macro defines the minimum header space */ | ||
87 | #define CDC_NCM_MIN_HDR_SIZE \ | ||
88 | (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \ | ||
89 | (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16)) | ||
90 | |||
91 | struct cdc_ncm_data { | ||
92 | struct usb_cdc_ncm_nth16 nth16; | ||
93 | struct usb_cdc_ncm_ndp16 ndp16; | ||
94 | struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1]; | ||
95 | }; | ||
96 | |||
97 | struct cdc_ncm_ctx { | ||
98 | struct cdc_ncm_data rx_ncm; | ||
99 | struct cdc_ncm_data tx_ncm; | ||
100 | struct usb_cdc_ncm_ntb_parameters ncm_parm; | ||
101 | struct timer_list tx_timer; | ||
102 | |||
103 | const struct usb_cdc_ncm_desc *func_desc; | ||
104 | const struct usb_cdc_header_desc *header_desc; | ||
105 | const struct usb_cdc_union_desc *union_desc; | ||
106 | const struct usb_cdc_ether_desc *ether_desc; | ||
107 | |||
108 | struct net_device *netdev; | ||
109 | struct usb_device *udev; | ||
110 | struct usb_host_endpoint *in_ep; | ||
111 | struct usb_host_endpoint *out_ep; | ||
112 | struct usb_host_endpoint *status_ep; | ||
113 | struct usb_interface *intf; | ||
114 | struct usb_interface *control; | ||
115 | struct usb_interface *data; | ||
116 | |||
117 | struct sk_buff *tx_curr_skb; | ||
118 | struct sk_buff *tx_rem_skb; | ||
119 | |||
120 | spinlock_t mtx; | ||
121 | |||
122 | u32 tx_timer_pending; | ||
123 | u32 tx_curr_offset; | ||
124 | u32 tx_curr_last_offset; | ||
125 | u32 tx_curr_frame_num; | ||
126 | u32 rx_speed; | ||
127 | u32 tx_speed; | ||
128 | u32 rx_max; | ||
129 | u32 tx_max; | ||
130 | u32 max_datagram_size; | ||
131 | u16 tx_max_datagrams; | ||
132 | u16 tx_remainder; | ||
133 | u16 tx_modulus; | ||
134 | u16 tx_ndp_modulus; | ||
135 | u16 tx_seq; | ||
136 | u16 connected; | ||
137 | }; | ||
138 | |||
139 | static void cdc_ncm_tx_timeout(unsigned long arg); | ||
140 | static const struct driver_info cdc_ncm_info; | ||
141 | static struct usb_driver cdc_ncm_driver; | ||
142 | static struct ethtool_ops cdc_ncm_ethtool_ops; | ||
143 | |||
144 | static const struct usb_device_id cdc_devs[] = { | ||
145 | { USB_INTERFACE_INFO(USB_CLASS_COMM, | ||
146 | USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE), | ||
147 | .driver_info = (unsigned long)&cdc_ncm_info, | ||
148 | }, | ||
149 | { | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | MODULE_DEVICE_TABLE(usb, cdc_devs); | ||
154 | |||
155 | static void | ||
156 | cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | ||
157 | { | ||
158 | struct usbnet *dev = netdev_priv(net); | ||
159 | |||
160 | strncpy(info->driver, dev->driver_name, sizeof(info->driver)); | ||
161 | strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); | ||
162 | strncpy(info->fw_version, dev->driver_info->description, | ||
163 | sizeof(info->fw_version)); | ||
164 | usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); | ||
165 | } | ||
166 | |||
167 | static int | ||
168 | cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req, | ||
169 | void *data, u16 flags, u16 *actlen, u16 timeout) | ||
170 | { | ||
171 | int err; | ||
172 | |||
173 | err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ? | ||
174 | usb_rcvctrlpipe(ctx->udev, 0) : | ||
175 | usb_sndctrlpipe(ctx->udev, 0), | ||
176 | req->bNotificationType, req->bmRequestType, | ||
177 | req->wValue, | ||
178 | req->wIndex, data, | ||
179 | req->wLength, timeout); | ||
180 | |||
181 | if (err < 0) { | ||
182 | if (actlen) | ||
183 | *actlen = 0; | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | if (actlen) | ||
188 | *actlen = err; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) | ||
194 | { | ||
195 | struct usb_cdc_notification req; | ||
196 | u32 val; | ||
197 | u8 flags; | ||
198 | u8 iface_no; | ||
199 | int err; | ||
200 | u16 ntb_fmt_supported; | ||
201 | |||
202 | iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; | ||
203 | |||
204 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE; | ||
205 | req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS; | ||
206 | req.wValue = 0; | ||
207 | req.wIndex = cpu_to_le16(iface_no); | ||
208 | req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm)); | ||
209 | |||
210 | err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000); | ||
211 | if (err) { | ||
212 | pr_debug("failed GET_NTB_PARAMETERS\n"); | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | /* read correct set of parameters according to device mode */ | ||
217 | ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize); | ||
218 | ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize); | ||
219 | ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder); | ||
220 | ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor); | ||
221 | ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment); | ||
222 | /* devices prior to NCM Errata shall set this field to zero */ | ||
223 | ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams); | ||
224 | ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported); | ||
225 | |||
226 | if (ctx->func_desc != NULL) | ||
227 | flags = ctx->func_desc->bmNetworkCapabilities; | ||
228 | else | ||
229 | flags = 0; | ||
230 | |||
231 | pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u " | ||
232 | "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u " | ||
233 | "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n", | ||
234 | ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus, | ||
235 | ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags); | ||
236 | |||
237 | /* max count of tx datagrams */ | ||
238 | if ((ctx->tx_max_datagrams == 0) || | ||
239 | (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX)) | ||
240 | ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX; | ||
241 | |||
242 | /* verify maximum size of received NTB in bytes */ | ||
243 | if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) { | ||
244 | pr_debug("Using min receive length=%d\n", | ||
245 | USB_CDC_NCM_NTB_MIN_IN_SIZE); | ||
246 | ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE; | ||
247 | } | ||
248 | |||
249 | if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) { | ||
250 | pr_debug("Using default maximum receive length=%d\n", | ||
251 | CDC_NCM_NTB_MAX_SIZE_RX); | ||
252 | ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX; | ||
253 | } | ||
254 | |||
255 | /* inform device about NTB input size changes */ | ||
256 | if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { | ||
257 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | | ||
258 | USB_RECIP_INTERFACE; | ||
259 | req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE; | ||
260 | req.wValue = 0; | ||
261 | req.wIndex = cpu_to_le16(iface_no); | ||
262 | |||
263 | if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { | ||
264 | struct usb_cdc_ncm_ndp_input_size ndp_in_sz; | ||
265 | |||
266 | req.wLength = 8; | ||
267 | ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); | ||
268 | ndp_in_sz.wNtbInMaxDatagrams = | ||
269 | cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX); | ||
270 | ndp_in_sz.wReserved = 0; | ||
271 | err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL, | ||
272 | 1000); | ||
273 | } else { | ||
274 | __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); | ||
275 | |||
276 | req.wLength = 4; | ||
277 | err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0, | ||
278 | NULL, 1000); | ||
279 | } | ||
280 | |||
281 | if (err) | ||
282 | pr_debug("Setting NTB Input Size failed\n"); | ||
283 | } | ||
284 | |||
285 | /* verify maximum size of transmitted NTB in bytes */ | ||
286 | if ((ctx->tx_max < | ||
287 | (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) || | ||
288 | (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) { | ||
289 | pr_debug("Using default maximum transmit length=%d\n", | ||
290 | CDC_NCM_NTB_MAX_SIZE_TX); | ||
291 | ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * verify that the structure alignment is: | ||
296 | * - power of two | ||
297 | * - not greater than the maximum transmit length | ||
298 | * - not less than four bytes | ||
299 | */ | ||
300 | val = ctx->tx_ndp_modulus; | ||
301 | |||
302 | if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || | ||
303 | (val != ((-val) & val)) || (val >= ctx->tx_max)) { | ||
304 | pr_debug("Using default alignment: 4 bytes\n"); | ||
305 | ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * verify that the payload alignment is: | ||
310 | * - power of two | ||
311 | * - not greater than the maximum transmit length | ||
312 | * - not less than four bytes | ||
313 | */ | ||
314 | val = ctx->tx_modulus; | ||
315 | |||
316 | if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) || | ||
317 | (val != ((-val) & val)) || (val >= ctx->tx_max)) { | ||
318 | pr_debug("Using default transmit modulus: 4 bytes\n"); | ||
319 | ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE; | ||
320 | } | ||
321 | |||
322 | /* verify the payload remainder */ | ||
323 | if (ctx->tx_remainder >= ctx->tx_modulus) { | ||
324 | pr_debug("Using default transmit remainder: 0 bytes\n"); | ||
325 | ctx->tx_remainder = 0; | ||
326 | } | ||
327 | |||
328 | /* adjust TX-remainder according to NCM specification. */ | ||
329 | ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) & | ||
330 | (ctx->tx_modulus - 1)); | ||
331 | |||
332 | /* additional configuration */ | ||
333 | |||
334 | /* set CRC Mode */ | ||
335 | if (flags & USB_CDC_NCM_NCAP_CRC_MODE) { | ||
336 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | | ||
337 | USB_RECIP_INTERFACE; | ||
338 | req.bNotificationType = USB_CDC_SET_CRC_MODE; | ||
339 | req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED); | ||
340 | req.wIndex = cpu_to_le16(iface_no); | ||
341 | req.wLength = 0; | ||
342 | |||
343 | err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); | ||
344 | if (err) | ||
345 | pr_debug("Setting CRC mode off failed\n"); | ||
346 | } | ||
347 | |||
348 | /* set NTB format, if both formats are supported */ | ||
349 | if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) { | ||
350 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | | ||
351 | USB_RECIP_INTERFACE; | ||
352 | req.bNotificationType = USB_CDC_SET_NTB_FORMAT; | ||
353 | req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT); | ||
354 | req.wIndex = cpu_to_le16(iface_no); | ||
355 | req.wLength = 0; | ||
356 | |||
357 | err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); | ||
358 | if (err) | ||
359 | pr_debug("Setting NTB format to 16-bit failed\n"); | ||
360 | } | ||
361 | |||
362 | ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE; | ||
363 | |||
364 | /* set Max Datagram Size (MTU) */ | ||
365 | if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { | ||
366 | __le16 max_datagram_size; | ||
367 | u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); | ||
368 | |||
369 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | | ||
370 | USB_RECIP_INTERFACE; | ||
371 | req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE; | ||
372 | req.wValue = 0; | ||
373 | req.wIndex = cpu_to_le16(iface_no); | ||
374 | req.wLength = cpu_to_le16(2); | ||
375 | |||
376 | err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, | ||
377 | 1000); | ||
378 | if (err) { | ||
379 | pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", | ||
380 | CDC_NCM_MIN_DATAGRAM_SIZE); | ||
381 | } else { | ||
382 | ctx->max_datagram_size = le16_to_cpu(max_datagram_size); | ||
383 | /* Check Eth descriptor value */ | ||
384 | if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) { | ||
385 | if (ctx->max_datagram_size > eth_max_sz) | ||
386 | ctx->max_datagram_size = eth_max_sz; | ||
387 | } else { | ||
388 | if (ctx->max_datagram_size > | ||
389 | CDC_NCM_MAX_DATAGRAM_SIZE) | ||
390 | ctx->max_datagram_size = | ||
391 | CDC_NCM_MAX_DATAGRAM_SIZE; | ||
392 | } | ||
393 | |||
394 | if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) | ||
395 | ctx->max_datagram_size = | ||
396 | CDC_NCM_MIN_DATAGRAM_SIZE; | ||
397 | |||
398 | /* if value changed, update device */ | ||
399 | req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | | ||
400 | USB_RECIP_INTERFACE; | ||
401 | req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE; | ||
402 | req.wValue = 0; | ||
403 | req.wIndex = cpu_to_le16(iface_no); | ||
404 | req.wLength = 2; | ||
405 | max_datagram_size = cpu_to_le16(ctx->max_datagram_size); | ||
406 | |||
407 | err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, | ||
408 | 0, NULL, 1000); | ||
409 | if (err) | ||
410 | pr_debug("SET_MAX_DATAGRAM_SIZE failed\n"); | ||
411 | } | ||
412 | |||
413 | } | ||
414 | |||
415 | if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN)) | ||
416 | ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN; | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static void | ||
422 | cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf) | ||
423 | { | ||
424 | struct usb_host_endpoint *e; | ||
425 | u8 ep; | ||
426 | |||
427 | for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { | ||
428 | |||
429 | e = intf->cur_altsetting->endpoint + ep; | ||
430 | switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
431 | case USB_ENDPOINT_XFER_INT: | ||
432 | if (usb_endpoint_dir_in(&e->desc)) { | ||
433 | if (ctx->status_ep == NULL) | ||
434 | ctx->status_ep = e; | ||
435 | } | ||
436 | break; | ||
437 | |||
438 | case USB_ENDPOINT_XFER_BULK: | ||
439 | if (usb_endpoint_dir_in(&e->desc)) { | ||
440 | if (ctx->in_ep == NULL) | ||
441 | ctx->in_ep = e; | ||
442 | } else { | ||
443 | if (ctx->out_ep == NULL) | ||
444 | ctx->out_ep = e; | ||
445 | } | ||
446 | break; | ||
447 | |||
448 | default: | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | |||
454 | static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) | ||
455 | { | ||
456 | if (ctx == NULL) | ||
457 | return; | ||
458 | |||
459 | del_timer_sync(&ctx->tx_timer); | ||
460 | |||
461 | if (ctx->tx_rem_skb != NULL) { | ||
462 | dev_kfree_skb_any(ctx->tx_rem_skb); | ||
463 | ctx->tx_rem_skb = NULL; | ||
464 | } | ||
465 | |||
466 | if (ctx->tx_curr_skb != NULL) { | ||
467 | dev_kfree_skb_any(ctx->tx_curr_skb); | ||
468 | ctx->tx_curr_skb = NULL; | ||
469 | } | ||
470 | |||
471 | kfree(ctx); | ||
472 | } | ||
473 | |||
474 | static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) | ||
475 | { | ||
476 | struct cdc_ncm_ctx *ctx; | ||
477 | struct usb_driver *driver; | ||
478 | u8 *buf; | ||
479 | int len; | ||
480 | int temp; | ||
481 | u8 iface_no; | ||
482 | |||
483 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
484 | if (ctx == NULL) | ||
485 | return -ENODEV; | ||
486 | |||
487 | memset(ctx, 0, sizeof(*ctx)); | ||
488 | |||
489 | init_timer(&ctx->tx_timer); | ||
490 | spin_lock_init(&ctx->mtx); | ||
491 | ctx->netdev = dev->net; | ||
492 | |||
493 | /* store ctx pointer in device data field */ | ||
494 | dev->data[0] = (unsigned long)ctx; | ||
495 | |||
496 | /* get some pointers */ | ||
497 | driver = driver_of(intf); | ||
498 | buf = intf->cur_altsetting->extra; | ||
499 | len = intf->cur_altsetting->extralen; | ||
500 | |||
501 | ctx->udev = dev->udev; | ||
502 | ctx->intf = intf; | ||
503 | |||
504 | /* parse through descriptors associated with control interface */ | ||
505 | while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) { | ||
506 | |||
507 | if (buf[1] != USB_DT_CS_INTERFACE) | ||
508 | goto advance; | ||
509 | |||
510 | switch (buf[2]) { | ||
511 | case USB_CDC_UNION_TYPE: | ||
512 | if (buf[0] < sizeof(*(ctx->union_desc))) | ||
513 | break; | ||
514 | |||
515 | ctx->union_desc = | ||
516 | (const struct usb_cdc_union_desc *)buf; | ||
517 | |||
518 | ctx->control = usb_ifnum_to_if(dev->udev, | ||
519 | ctx->union_desc->bMasterInterface0); | ||
520 | ctx->data = usb_ifnum_to_if(dev->udev, | ||
521 | ctx->union_desc->bSlaveInterface0); | ||
522 | break; | ||
523 | |||
524 | case USB_CDC_ETHERNET_TYPE: | ||
525 | if (buf[0] < sizeof(*(ctx->ether_desc))) | ||
526 | break; | ||
527 | |||
528 | ctx->ether_desc = | ||
529 | (const struct usb_cdc_ether_desc *)buf; | ||
530 | dev->hard_mtu = | ||
531 | le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); | ||
532 | |||
533 | if (dev->hard_mtu < CDC_NCM_MIN_DATAGRAM_SIZE) | ||
534 | dev->hard_mtu = CDC_NCM_MIN_DATAGRAM_SIZE; | ||
535 | else if (dev->hard_mtu > CDC_NCM_MAX_DATAGRAM_SIZE) | ||
536 | dev->hard_mtu = CDC_NCM_MAX_DATAGRAM_SIZE; | ||
537 | break; | ||
538 | |||
539 | case USB_CDC_NCM_TYPE: | ||
540 | if (buf[0] < sizeof(*(ctx->func_desc))) | ||
541 | break; | ||
542 | |||
543 | ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf; | ||
544 | break; | ||
545 | |||
546 | default: | ||
547 | break; | ||
548 | } | ||
549 | advance: | ||
550 | /* advance to next descriptor */ | ||
551 | temp = buf[0]; | ||
552 | buf += temp; | ||
553 | len -= temp; | ||
554 | } | ||
555 | |||
556 | /* check if we got everything */ | ||
557 | if ((ctx->control == NULL) || (ctx->data == NULL) || | ||
558 | (ctx->ether_desc == NULL) || (ctx->control != intf)) | ||
559 | goto error; | ||
560 | |||
561 | /* claim interfaces, if any */ | ||
562 | temp = usb_driver_claim_interface(driver, ctx->data, dev); | ||
563 | if (temp) | ||
564 | goto error; | ||
565 | |||
566 | iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber; | ||
567 | |||
568 | /* reset data interface */ | ||
569 | temp = usb_set_interface(dev->udev, iface_no, 0); | ||
570 | if (temp) | ||
571 | goto error2; | ||
572 | |||
573 | /* initialize data interface */ | ||
574 | if (cdc_ncm_setup(ctx)) | ||
575 | goto error2; | ||
576 | |||
577 | /* configure data interface */ | ||
578 | temp = usb_set_interface(dev->udev, iface_no, 1); | ||
579 | if (temp) | ||
580 | goto error2; | ||
581 | |||
582 | cdc_ncm_find_endpoints(ctx, ctx->data); | ||
583 | cdc_ncm_find_endpoints(ctx, ctx->control); | ||
584 | |||
585 | if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) || | ||
586 | (ctx->status_ep == NULL)) | ||
587 | goto error2; | ||
588 | |||
589 | dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; | ||
590 | |||
591 | usb_set_intfdata(ctx->data, dev); | ||
592 | usb_set_intfdata(ctx->control, dev); | ||
593 | usb_set_intfdata(ctx->intf, dev); | ||
594 | |||
595 | temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress); | ||
596 | if (temp) | ||
597 | goto error2; | ||
598 | |||
599 | dev_info(&dev->udev->dev, "MAC-Address: " | ||
600 | "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", | ||
601 | dev->net->dev_addr[0], dev->net->dev_addr[1], | ||
602 | dev->net->dev_addr[2], dev->net->dev_addr[3], | ||
603 | dev->net->dev_addr[4], dev->net->dev_addr[5]); | ||
604 | |||
605 | dev->in = usb_rcvbulkpipe(dev->udev, | ||
606 | ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | ||
607 | dev->out = usb_sndbulkpipe(dev->udev, | ||
608 | ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | ||
609 | dev->status = ctx->status_ep; | ||
610 | dev->rx_urb_size = ctx->rx_max; | ||
611 | |||
612 | /* | ||
613 | * We should get an event when network connection is "connected" or | ||
614 | * "disconnected". Set network connection in "disconnected" state | ||
615 | * (carrier is OFF) during attach, so the IP network stack does not | ||
616 | * start IPv6 negotiation and more. | ||
617 | */ | ||
618 | netif_carrier_off(dev->net); | ||
619 | ctx->tx_speed = ctx->rx_speed = 0; | ||
620 | return 0; | ||
621 | |||
622 | error2: | ||
623 | usb_set_intfdata(ctx->control, NULL); | ||
624 | usb_set_intfdata(ctx->data, NULL); | ||
625 | usb_driver_release_interface(driver, ctx->data); | ||
626 | error: | ||
627 | cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]); | ||
628 | dev->data[0] = 0; | ||
629 | dev_info(&dev->udev->dev, "bind() failure\n"); | ||
630 | return -ENODEV; | ||
631 | } | ||
632 | |||
633 | static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
634 | { | ||
635 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
636 | struct usb_driver *driver = driver_of(intf); | ||
637 | |||
638 | if (ctx == NULL) | ||
639 | return; /* no setup */ | ||
640 | |||
641 | /* disconnect master --> disconnect slave */ | ||
642 | if (intf == ctx->control && ctx->data) { | ||
643 | usb_set_intfdata(ctx->data, NULL); | ||
644 | usb_driver_release_interface(driver, ctx->data); | ||
645 | ctx->data = NULL; | ||
646 | |||
647 | } else if (intf == ctx->data && ctx->control) { | ||
648 | usb_set_intfdata(ctx->control, NULL); | ||
649 | usb_driver_release_interface(driver, ctx->control); | ||
650 | ctx->control = NULL; | ||
651 | } | ||
652 | |||
653 | usb_set_intfdata(ctx->intf, NULL); | ||
654 | cdc_ncm_free(ctx); | ||
655 | } | ||
656 | |||
657 | static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max) | ||
658 | { | ||
659 | if (first >= max) | ||
660 | return; | ||
661 | if (first >= end) | ||
662 | return; | ||
663 | if (end > max) | ||
664 | end = max; | ||
665 | memset(ptr + first, 0, end - first); | ||
666 | } | ||
667 | |||
668 | static struct sk_buff * | ||
669 | cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) | ||
670 | { | ||
671 | struct sk_buff *skb_out; | ||
672 | u32 rem; | ||
673 | u32 offset; | ||
674 | u32 last_offset; | ||
675 | u16 n = 0; | ||
676 | u8 ready2send = 0; | ||
677 | |||
678 | /* if there is a remaining skb, it gets priority */ | ||
679 | if (skb != NULL) | ||
680 | swap(skb, ctx->tx_rem_skb); | ||
681 | else | ||
682 | ready2send = 1; | ||
683 | |||
684 | /* | ||
685 | * +----------------+ | ||
686 | * | skb_out | | ||
687 | * +----------------+ | ||
688 | * ^ offset | ||
689 | * ^ last_offset | ||
690 | */ | ||
691 | |||
692 | /* check if we are resuming an OUT skb */ | ||
693 | if (ctx->tx_curr_skb != NULL) { | ||
694 | /* pop variables */ | ||
695 | skb_out = ctx->tx_curr_skb; | ||
696 | offset = ctx->tx_curr_offset; | ||
697 | last_offset = ctx->tx_curr_last_offset; | ||
698 | n = ctx->tx_curr_frame_num; | ||
699 | |||
700 | } else { | ||
701 | /* reset variables */ | ||
702 | skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC); | ||
703 | if (skb_out == NULL) { | ||
704 | if (skb != NULL) { | ||
705 | dev_kfree_skb_any(skb); | ||
706 | ctx->netdev->stats.tx_dropped++; | ||
707 | } | ||
708 | goto exit_no_skb; | ||
709 | } | ||
710 | |||
711 | /* make room for NTH and NDP */ | ||
712 | offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16), | ||
713 | ctx->tx_ndp_modulus) + | ||
714 | sizeof(struct usb_cdc_ncm_ndp16) + | ||
715 | (ctx->tx_max_datagrams + 1) * | ||
716 | sizeof(struct usb_cdc_ncm_dpe16); | ||
717 | |||
718 | /* store last valid offset before alignment */ | ||
719 | last_offset = offset; | ||
720 | /* align first Datagram offset correctly */ | ||
721 | offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; | ||
722 | /* zero buffer till the first IP datagram */ | ||
723 | cdc_ncm_zero_fill(skb_out->data, 0, offset, offset); | ||
724 | n = 0; | ||
725 | ctx->tx_curr_frame_num = 0; | ||
726 | } | ||
727 | |||
728 | for (; n < ctx->tx_max_datagrams; n++) { | ||
729 | /* check if end of transmit buffer is reached */ | ||
730 | if (offset >= ctx->tx_max) { | ||
731 | ready2send = 1; | ||
732 | break; | ||
733 | } | ||
734 | /* compute maximum buffer size */ | ||
735 | rem = ctx->tx_max - offset; | ||
736 | |||
737 | if (skb == NULL) { | ||
738 | skb = ctx->tx_rem_skb; | ||
739 | ctx->tx_rem_skb = NULL; | ||
740 | |||
741 | /* check for end of skb */ | ||
742 | if (skb == NULL) | ||
743 | break; | ||
744 | } | ||
745 | |||
746 | if (skb->len > rem) { | ||
747 | if (n == 0) { | ||
748 | /* won't fit, MTU problem? */ | ||
749 | dev_kfree_skb_any(skb); | ||
750 | skb = NULL; | ||
751 | ctx->netdev->stats.tx_dropped++; | ||
752 | } else { | ||
753 | /* no room for skb - store for later */ | ||
754 | if (ctx->tx_rem_skb != NULL) { | ||
755 | dev_kfree_skb_any(ctx->tx_rem_skb); | ||
756 | ctx->netdev->stats.tx_dropped++; | ||
757 | } | ||
758 | ctx->tx_rem_skb = skb; | ||
759 | skb = NULL; | ||
760 | ready2send = 1; | ||
761 | } | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len); | ||
766 | |||
767 | ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len); | ||
768 | ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset); | ||
769 | |||
770 | /* update offset */ | ||
771 | offset += skb->len; | ||
772 | |||
773 | /* store last valid offset before alignment */ | ||
774 | last_offset = offset; | ||
775 | |||
776 | /* align offset correctly */ | ||
777 | offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder; | ||
778 | |||
779 | /* zero padding */ | ||
780 | cdc_ncm_zero_fill(skb_out->data, last_offset, offset, | ||
781 | ctx->tx_max); | ||
782 | dev_kfree_skb_any(skb); | ||
783 | skb = NULL; | ||
784 | } | ||
785 | |||
786 | /* free up any dangling skb */ | ||
787 | if (skb != NULL) { | ||
788 | dev_kfree_skb_any(skb); | ||
789 | skb = NULL; | ||
790 | ctx->netdev->stats.tx_dropped++; | ||
791 | } | ||
792 | |||
793 | ctx->tx_curr_frame_num = n; | ||
794 | |||
795 | if (n == 0) { | ||
796 | /* wait for more frames */ | ||
797 | /* push variables */ | ||
798 | ctx->tx_curr_skb = skb_out; | ||
799 | ctx->tx_curr_offset = offset; | ||
800 | ctx->tx_curr_last_offset = last_offset; | ||
801 | goto exit_no_skb; | ||
802 | |||
803 | } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { | ||
804 | /* wait for more frames */ | ||
805 | /* push variables */ | ||
806 | ctx->tx_curr_skb = skb_out; | ||
807 | ctx->tx_curr_offset = offset; | ||
808 | ctx->tx_curr_last_offset = last_offset; | ||
809 | /* set the pending count */ | ||
810 | if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT) | ||
811 | ctx->tx_timer_pending = 2; | ||
812 | goto exit_no_skb; | ||
813 | |||
814 | } else { | ||
815 | /* frame goes out */ | ||
816 | /* variables will be reset at next call */ | ||
817 | } | ||
818 | |||
819 | /* check for overflow */ | ||
820 | if (last_offset > ctx->tx_max) | ||
821 | last_offset = ctx->tx_max; | ||
822 | |||
823 | /* revert offset */ | ||
824 | offset = last_offset; | ||
825 | |||
826 | /* | ||
827 | * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes, | ||
828 | * we send buffers as it is. If we get more data, it would be more | ||
829 | * efficient for USB HS mobile device with DMA engine to receive a full | ||
830 | * size NTB, than canceling DMA transfer and receiving a short packet. | ||
831 | */ | ||
832 | if (offset > CDC_NCM_MIN_TX_PKT) | ||
833 | offset = ctx->tx_max; | ||
834 | |||
835 | /* final zero padding */ | ||
836 | cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max); | ||
837 | |||
838 | /* store last offset */ | ||
839 | last_offset = offset; | ||
840 | |||
841 | if (((last_offset < ctx->tx_max) && ((last_offset % | ||
842 | le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) || | ||
843 | (((last_offset == ctx->tx_max) && ((ctx->tx_max % | ||
844 | le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) && | ||
845 | (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) { | ||
846 | /* force short packet */ | ||
847 | *(((u8 *)skb_out->data) + last_offset) = 0; | ||
848 | last_offset++; | ||
849 | } | ||
850 | |||
851 | /* zero the rest of the DPEs plus the last NULL entry */ | ||
852 | for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) { | ||
853 | ctx->tx_ncm.dpe16[n].wDatagramLength = 0; | ||
854 | ctx->tx_ncm.dpe16[n].wDatagramIndex = 0; | ||
855 | } | ||
856 | |||
857 | /* fill out 16-bit NTB header */ | ||
858 | ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN); | ||
859 | ctx->tx_ncm.nth16.wHeaderLength = | ||
860 | cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); | ||
861 | ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); | ||
862 | ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); | ||
863 | ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16), | ||
864 | ctx->tx_ndp_modulus); | ||
865 | |||
866 | memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); | ||
867 | ctx->tx_seq++; | ||
868 | |||
869 | /* fill out 16-bit NDP table */ | ||
870 | ctx->tx_ncm.ndp16.dwSignature = | ||
871 | cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN); | ||
872 | rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) * | ||
873 | sizeof(struct usb_cdc_ncm_dpe16)); | ||
874 | ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); | ||
875 | ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ | ||
876 | |||
877 | memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex, | ||
878 | &(ctx->tx_ncm.ndp16), | ||
879 | sizeof(ctx->tx_ncm.ndp16)); | ||
880 | |||
881 | memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex + | ||
882 | sizeof(ctx->tx_ncm.ndp16), | ||
883 | &(ctx->tx_ncm.dpe16), | ||
884 | (ctx->tx_curr_frame_num + 1) * | ||
885 | sizeof(struct usb_cdc_ncm_dpe16)); | ||
886 | |||
887 | /* set frame length */ | ||
888 | skb_put(skb_out, last_offset); | ||
889 | |||
890 | /* return skb */ | ||
891 | ctx->tx_curr_skb = NULL; | ||
892 | return skb_out; | ||
893 | |||
894 | exit_no_skb: | ||
895 | return NULL; | ||
896 | } | ||
897 | |||
898 | static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx) | ||
899 | { | ||
900 | /* start timer, if not already started */ | ||
901 | if (timer_pending(&ctx->tx_timer) == 0) { | ||
902 | ctx->tx_timer.function = &cdc_ncm_tx_timeout; | ||
903 | ctx->tx_timer.data = (unsigned long)ctx; | ||
904 | ctx->tx_timer.expires = jiffies + ((HZ + 999) / 1000); | ||
905 | add_timer(&ctx->tx_timer); | ||
906 | } | ||
907 | } | ||
908 | |||
909 | static void cdc_ncm_tx_timeout(unsigned long arg) | ||
910 | { | ||
911 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)arg; | ||
912 | u8 restart; | ||
913 | |||
914 | spin_lock(&ctx->mtx); | ||
915 | if (ctx->tx_timer_pending != 0) { | ||
916 | ctx->tx_timer_pending--; | ||
917 | restart = 1; | ||
918 | } else { | ||
919 | restart = 0; | ||
920 | } | ||
921 | |||
922 | spin_unlock(&ctx->mtx); | ||
923 | |||
924 | if (restart) { | ||
925 | spin_lock(&ctx->mtx); | ||
926 | cdc_ncm_tx_timeout_start(ctx); | ||
927 | spin_unlock(&ctx->mtx); | ||
928 | } else if (ctx->netdev != NULL) { | ||
929 | usbnet_start_xmit(NULL, ctx->netdev); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | static struct sk_buff * | ||
934 | cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
935 | { | ||
936 | struct sk_buff *skb_out; | ||
937 | struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
938 | u8 need_timer = 0; | ||
939 | |||
940 | /* | ||
941 | * The Ethernet API we are using does not support transmitting | ||
942 | * multiple Ethernet frames in a single call. This driver will | ||
943 | * accumulate multiple Ethernet frames and send out a larger | ||
944 | * USB frame when the USB buffer is full or when a single jiffies | ||
945 | * timeout happens. | ||
946 | */ | ||
947 | if (ctx == NULL) | ||
948 | goto error; | ||
949 | |||
950 | spin_lock(&ctx->mtx); | ||
951 | skb_out = cdc_ncm_fill_tx_frame(ctx, skb); | ||
952 | if (ctx->tx_curr_skb != NULL) | ||
953 | need_timer = 1; | ||
954 | |||
955 | /* Start timer, if there is a remaining skb */ | ||
956 | if (need_timer) | ||
957 | cdc_ncm_tx_timeout_start(ctx); | ||
958 | |||
959 | if (skb_out) | ||
960 | dev->net->stats.tx_packets += ctx->tx_curr_frame_num; | ||
961 | |||
962 | spin_unlock(&ctx->mtx); | ||
963 | return skb_out; | ||
964 | |||
965 | error: | ||
966 | if (skb != NULL) | ||
967 | dev_kfree_skb_any(skb); | ||
968 | |||
969 | return NULL; | ||
970 | } | ||
971 | |||
972 | static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) | ||
973 | { | ||
974 | struct sk_buff *skb; | ||
975 | struct cdc_ncm_ctx *ctx; | ||
976 | int sumlen; | ||
977 | int actlen; | ||
978 | int temp; | ||
979 | int nframes; | ||
980 | int x; | ||
981 | int offset; | ||
982 | |||
983 | ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
984 | if (ctx == NULL) | ||
985 | goto error; | ||
986 | |||
987 | actlen = skb_in->len; | ||
988 | sumlen = CDC_NCM_NTB_MAX_SIZE_RX; | ||
989 | |||
990 | if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) { | ||
991 | pr_debug("frame too short\n"); | ||
992 | goto error; | ||
993 | } | ||
994 | |||
995 | memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data), | ||
996 | sizeof(ctx->rx_ncm.nth16)); | ||
997 | |||
998 | if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) != | ||
999 | USB_CDC_NCM_NTH16_SIGN) { | ||
1000 | pr_debug("invalid NTH16 signature <%u>\n", | ||
1001 | le32_to_cpu(ctx->rx_ncm.nth16.dwSignature)); | ||
1002 | goto error; | ||
1003 | } | ||
1004 | |||
1005 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength); | ||
1006 | if (temp > sumlen) { | ||
1007 | pr_debug("unsupported NTB block length %u/%u\n", temp, sumlen); | ||
1008 | goto error; | ||
1009 | } | ||
1010 | |||
1011 | temp = le16_to_cpu(ctx->rx_ncm.nth16.wNdpIndex); | ||
1012 | if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) { | ||
1013 | pr_debug("invalid DPT16 index\n"); | ||
1014 | goto error; | ||
1015 | } | ||
1016 | |||
1017 | memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp, | ||
1018 | sizeof(ctx->rx_ncm.ndp16)); | ||
1019 | |||
1020 | if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) != | ||
1021 | USB_CDC_NCM_NDP16_NOCRC_SIGN) { | ||
1022 | pr_debug("invalid DPT16 signature <%u>\n", | ||
1023 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | ||
1024 | goto error; | ||
1025 | } | ||
1026 | |||
1027 | if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) < | ||
1028 | USB_CDC_NCM_NDP16_LENGTH_MIN) { | ||
1029 | pr_debug("invalid DPT16 length <%u>\n", | ||
1030 | le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature)); | ||
1031 | goto error; | ||
1032 | } | ||
1033 | |||
1034 | nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) - | ||
1035 | sizeof(struct usb_cdc_ncm_ndp16)) / | ||
1036 | sizeof(struct usb_cdc_ncm_dpe16)); | ||
1037 | nframes--; /* we process NDP entries except for the last one */ | ||
1038 | |||
1039 | pr_debug("nframes = %u\n", nframes); | ||
1040 | |||
1041 | temp += sizeof(ctx->rx_ncm.ndp16); | ||
1042 | |||
1043 | if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) { | ||
1044 | pr_debug("Invalid nframes = %d\n", nframes); | ||
1045 | goto error; | ||
1046 | } | ||
1047 | |||
1048 | if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) { | ||
1049 | pr_debug("Truncating number of frames from %u to %u\n", | ||
1050 | nframes, CDC_NCM_DPT_DATAGRAMS_MAX); | ||
1051 | nframes = CDC_NCM_DPT_DATAGRAMS_MAX; | ||
1052 | } | ||
1053 | |||
1054 | memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp, | ||
1055 | nframes * (sizeof(struct usb_cdc_ncm_dpe16))); | ||
1056 | |||
1057 | for (x = 0; x < nframes; x++) { | ||
1058 | offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex); | ||
1059 | temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength); | ||
1060 | |||
1061 | /* | ||
1062 | * CDC NCM ch. 3.7 | ||
1063 | * All entries after first NULL entry are to be ignored | ||
1064 | */ | ||
1065 | if ((offset == 0) || (temp == 0)) { | ||
1066 | if (!x) | ||
1067 | goto error; /* empty NTB */ | ||
1068 | break; | ||
1069 | } | ||
1070 | |||
1071 | /* sanity checking */ | ||
1072 | if (((offset + temp) > actlen) || | ||
1073 | (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) { | ||
1074 | pr_debug("invalid frame detected (ignored)" | ||
1075 | "offset[%u]=%u, length=%u, skb=%p\n", | ||
1076 | x, offset, temp, skb_in); | ||
1077 | if (!x) | ||
1078 | goto error; | ||
1079 | break; | ||
1080 | |||
1081 | } else { | ||
1082 | skb = skb_clone(skb_in, GFP_ATOMIC); | ||
1083 | if (!skb) | ||
1084 | goto error; | ||
1085 | skb->len = temp; | ||
1086 | skb->data = ((u8 *)skb_in->data) + offset; | ||
1087 | skb_set_tail_pointer(skb, temp); | ||
1088 | usbnet_skb_return(dev, skb); | ||
1089 | } | ||
1090 | } | ||
1091 | return 1; | ||
1092 | error: | ||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | static void | ||
1097 | cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx, | ||
1098 | struct usb_cdc_speed_change *data) | ||
1099 | { | ||
1100 | uint32_t rx_speed = le32_to_cpu(data->DLBitRRate); | ||
1101 | uint32_t tx_speed = le32_to_cpu(data->ULBitRate); | ||
1102 | |||
1103 | /* | ||
1104 | * Currently the USB-NET API does not support reporting the actual | ||
1105 | * device speed. Do print it instead. | ||
1106 | */ | ||
1107 | if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) { | ||
1108 | ctx->tx_speed = tx_speed; | ||
1109 | ctx->rx_speed = rx_speed; | ||
1110 | |||
1111 | if ((tx_speed > 1000000) && (rx_speed > 1000000)) { | ||
1112 | printk(KERN_INFO KBUILD_MODNAME | ||
1113 | ": %s: %u mbit/s downlink " | ||
1114 | "%u mbit/s uplink\n", | ||
1115 | ctx->netdev->name, | ||
1116 | (unsigned int)(rx_speed / 1000000U), | ||
1117 | (unsigned int)(tx_speed / 1000000U)); | ||
1118 | } else { | ||
1119 | printk(KERN_INFO KBUILD_MODNAME | ||
1120 | ": %s: %u kbit/s downlink " | ||
1121 | "%u kbit/s uplink\n", | ||
1122 | ctx->netdev->name, | ||
1123 | (unsigned int)(rx_speed / 1000U), | ||
1124 | (unsigned int)(tx_speed / 1000U)); | ||
1125 | } | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | static void cdc_ncm_status(struct usbnet *dev, struct urb *urb) | ||
1130 | { | ||
1131 | struct cdc_ncm_ctx *ctx; | ||
1132 | struct usb_cdc_notification *event; | ||
1133 | |||
1134 | ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
1135 | |||
1136 | if (urb->actual_length < sizeof(*event)) | ||
1137 | return; | ||
1138 | |||
1139 | /* test for split data in 8-byte chunks */ | ||
1140 | if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { | ||
1141 | cdc_ncm_speed_change(ctx, | ||
1142 | (struct usb_cdc_speed_change *)urb->transfer_buffer); | ||
1143 | return; | ||
1144 | } | ||
1145 | |||
1146 | event = urb->transfer_buffer; | ||
1147 | |||
1148 | switch (event->bNotificationType) { | ||
1149 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | ||
1150 | /* | ||
1151 | * According to the CDC NCM specification ch.7.1 | ||
1152 | * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be | ||
1153 | * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE. | ||
1154 | */ | ||
1155 | ctx->connected = event->wValue; | ||
1156 | |||
1157 | printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:" | ||
1158 | " %sconnected\n", | ||
1159 | ctx->netdev->name, ctx->connected ? "" : "dis"); | ||
1160 | |||
1161 | if (ctx->connected) | ||
1162 | netif_carrier_on(dev->net); | ||
1163 | else { | ||
1164 | netif_carrier_off(dev->net); | ||
1165 | ctx->tx_speed = ctx->rx_speed = 0; | ||
1166 | } | ||
1167 | break; | ||
1168 | |||
1169 | case USB_CDC_NOTIFY_SPEED_CHANGE: | ||
1170 | if (urb->actual_length < (sizeof(*event) + | ||
1171 | sizeof(struct usb_cdc_speed_change))) | ||
1172 | set_bit(EVENT_STS_SPLIT, &dev->flags); | ||
1173 | else | ||
1174 | cdc_ncm_speed_change(ctx, | ||
1175 | (struct usb_cdc_speed_change *) &event[1]); | ||
1176 | break; | ||
1177 | |||
1178 | default: | ||
1179 | dev_err(&dev->udev->dev, "NCM: unexpected " | ||
1180 | "notification 0x%02x!\n", event->bNotificationType); | ||
1181 | break; | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | static int cdc_ncm_check_connect(struct usbnet *dev) | ||
1186 | { | ||
1187 | struct cdc_ncm_ctx *ctx; | ||
1188 | |||
1189 | ctx = (struct cdc_ncm_ctx *)dev->data[0]; | ||
1190 | if (ctx == NULL) | ||
1191 | return 1; /* disconnected */ | ||
1192 | |||
1193 | return !ctx->connected; | ||
1194 | } | ||
1195 | |||
1196 | static int | ||
1197 | cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod) | ||
1198 | { | ||
1199 | return usbnet_probe(udev, prod); | ||
1200 | } | ||
1201 | |||
1202 | static void cdc_ncm_disconnect(struct usb_interface *intf) | ||
1203 | { | ||
1204 | struct usbnet *dev = usb_get_intfdata(intf); | ||
1205 | |||
1206 | if (dev == NULL) | ||
1207 | return; /* already disconnected */ | ||
1208 | |||
1209 | usbnet_disconnect(intf); | ||
1210 | } | ||
1211 | |||
1212 | static int cdc_ncm_manage_power(struct usbnet *dev, int status) | ||
1213 | { | ||
1214 | dev->intf->needs_remote_wakeup = status; | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | static const struct driver_info cdc_ncm_info = { | ||
1219 | .description = "CDC NCM", | ||
1220 | .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, | ||
1221 | .bind = cdc_ncm_bind, | ||
1222 | .unbind = cdc_ncm_unbind, | ||
1223 | .check_connect = cdc_ncm_check_connect, | ||
1224 | .manage_power = cdc_ncm_manage_power, | ||
1225 | .status = cdc_ncm_status, | ||
1226 | .rx_fixup = cdc_ncm_rx_fixup, | ||
1227 | .tx_fixup = cdc_ncm_tx_fixup, | ||
1228 | }; | ||
1229 | |||
1230 | static struct usb_driver cdc_ncm_driver = { | ||
1231 | .name = "cdc_ncm", | ||
1232 | .id_table = cdc_devs, | ||
1233 | .probe = cdc_ncm_probe, | ||
1234 | .disconnect = cdc_ncm_disconnect, | ||
1235 | .suspend = usbnet_suspend, | ||
1236 | .resume = usbnet_resume, | ||
1237 | .reset_resume = usbnet_resume, | ||
1238 | .supports_autosuspend = 1, | ||
1239 | }; | ||
1240 | |||
1241 | static struct ethtool_ops cdc_ncm_ethtool_ops = { | ||
1242 | .get_drvinfo = cdc_ncm_get_drvinfo, | ||
1243 | .get_link = usbnet_get_link, | ||
1244 | .get_msglevel = usbnet_get_msglevel, | ||
1245 | .set_msglevel = usbnet_set_msglevel, | ||
1246 | .get_settings = usbnet_get_settings, | ||
1247 | .set_settings = usbnet_set_settings, | ||
1248 | .nway_reset = usbnet_nway_reset, | ||
1249 | }; | ||
1250 | |||
1251 | static int __init cdc_ncm_init(void) | ||
1252 | { | ||
1253 | printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION "\n"); | ||
1254 | return usb_register(&cdc_ncm_driver); | ||
1255 | } | ||
1256 | |||
1257 | module_init(cdc_ncm_init); | ||
1258 | |||
1259 | static void __exit cdc_ncm_exit(void) | ||
1260 | { | ||
1261 | usb_deregister(&cdc_ncm_driver); | ||
1262 | } | ||
1263 | |||
1264 | module_exit(cdc_ncm_exit); | ||
1265 | |||
1266 | MODULE_AUTHOR("Hans Petter Selasky"); | ||
1267 | MODULE_DESCRIPTION("USB CDC NCM host driver"); | ||
1268 | MODULE_LICENSE("Dual BSD/GPL"); | ||
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index ca39ace0b0eb..fc5f13d47ad9 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c | |||
@@ -89,6 +89,7 @@ static int always_connected (struct usbnet *dev) | |||
89 | 89 | ||
90 | static const struct driver_info ali_m5632_info = { | 90 | static const struct driver_info ali_m5632_info = { |
91 | .description = "ALi M5632", | 91 | .description = "ALi M5632", |
92 | .flags = FLAG_POINTTOPOINT, | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | #endif | 95 | #endif |
@@ -110,6 +111,7 @@ static const struct driver_info ali_m5632_info = { | |||
110 | 111 | ||
111 | static const struct driver_info an2720_info = { | 112 | static const struct driver_info an2720_info = { |
112 | .description = "AnchorChips/Cypress 2720", | 113 | .description = "AnchorChips/Cypress 2720", |
114 | .flags = FLAG_POINTTOPOINT, | ||
113 | // no reset available! | 115 | // no reset available! |
114 | // no check_connect available! | 116 | // no check_connect available! |
115 | 117 | ||
@@ -132,6 +134,7 @@ static const struct driver_info an2720_info = { | |||
132 | 134 | ||
133 | static const struct driver_info belkin_info = { | 135 | static const struct driver_info belkin_info = { |
134 | .description = "Belkin, eTEK, or compatible", | 136 | .description = "Belkin, eTEK, or compatible", |
137 | .flags = FLAG_POINTTOPOINT, | ||
135 | }; | 138 | }; |
136 | 139 | ||
137 | #endif /* CONFIG_USB_BELKIN */ | 140 | #endif /* CONFIG_USB_BELKIN */ |
@@ -157,6 +160,7 @@ static const struct driver_info belkin_info = { | |||
157 | static const struct driver_info epson2888_info = { | 160 | static const struct driver_info epson2888_info = { |
158 | .description = "Epson USB Device", | 161 | .description = "Epson USB Device", |
159 | .check_connect = always_connected, | 162 | .check_connect = always_connected, |
163 | .flags = FLAG_POINTTOPOINT, | ||
160 | 164 | ||
161 | .in = 4, .out = 3, | 165 | .in = 4, .out = 3, |
162 | }; | 166 | }; |
@@ -173,6 +177,7 @@ static const struct driver_info epson2888_info = { | |||
173 | #define HAVE_HARDWARE | 177 | #define HAVE_HARDWARE |
174 | static const struct driver_info kc2190_info = { | 178 | static const struct driver_info kc2190_info = { |
175 | .description = "KC Technology KC-190", | 179 | .description = "KC Technology KC-190", |
180 | .flags = FLAG_POINTTOPOINT, | ||
176 | }; | 181 | }; |
177 | #endif /* CONFIG_USB_KC2190 */ | 182 | #endif /* CONFIG_USB_KC2190 */ |
178 | 183 | ||
@@ -200,16 +205,19 @@ static const struct driver_info kc2190_info = { | |||
200 | static const struct driver_info linuxdev_info = { | 205 | static const struct driver_info linuxdev_info = { |
201 | .description = "Linux Device", | 206 | .description = "Linux Device", |
202 | .check_connect = always_connected, | 207 | .check_connect = always_connected, |
208 | .flags = FLAG_POINTTOPOINT, | ||
203 | }; | 209 | }; |
204 | 210 | ||
205 | static const struct driver_info yopy_info = { | 211 | static const struct driver_info yopy_info = { |
206 | .description = "Yopy", | 212 | .description = "Yopy", |
207 | .check_connect = always_connected, | 213 | .check_connect = always_connected, |
214 | .flags = FLAG_POINTTOPOINT, | ||
208 | }; | 215 | }; |
209 | 216 | ||
210 | static const struct driver_info blob_info = { | 217 | static const struct driver_info blob_info = { |
211 | .description = "Boot Loader OBject", | 218 | .description = "Boot Loader OBject", |
212 | .check_connect = always_connected, | 219 | .check_connect = always_connected, |
220 | .flags = FLAG_POINTTOPOINT, | ||
213 | }; | 221 | }; |
214 | 222 | ||
215 | #endif /* CONFIG_USB_ARMLINUX */ | 223 | #endif /* CONFIG_USB_ARMLINUX */ |
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c new file mode 100644 index 000000000000..8969f124c18c --- /dev/null +++ b/drivers/net/usb/cx82310_eth.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * Driver for USB ethernet port of Conexant CX82310-based ADSL routers | ||
3 | * Copyright (C) 2010 by Ondrej Zary | ||
4 | * some parts inspired by the cxacru driver | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/netdevice.h> | ||
24 | #include <linux/etherdevice.h> | ||
25 | #include <linux/ethtool.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/mii.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/usb/usbnet.h> | ||
30 | |||
31 | enum cx82310_cmd { | ||
32 | CMD_START = 0x84, /* no effect? */ | ||
33 | CMD_STOP = 0x85, /* no effect? */ | ||
34 | CMD_GET_STATUS = 0x90, /* returns nothing? */ | ||
35 | CMD_GET_MAC_ADDR = 0x91, /* read MAC address */ | ||
36 | CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */ | ||
37 | CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */ | ||
38 | }; | ||
39 | |||
40 | enum cx82310_status { | ||
41 | STATUS_UNDEFINED, | ||
42 | STATUS_SUCCESS, | ||
43 | STATUS_ERROR, | ||
44 | STATUS_UNSUPPORTED, | ||
45 | STATUS_UNIMPLEMENTED, | ||
46 | STATUS_PARAMETER_ERROR, | ||
47 | STATUS_DBG_LOOPBACK, | ||
48 | }; | ||
49 | |||
50 | #define CMD_PACKET_SIZE 64 | ||
51 | /* first command after power on can take around 8 seconds */ | ||
52 | #define CMD_TIMEOUT 15000 | ||
53 | #define CMD_REPLY_RETRY 5 | ||
54 | |||
55 | #define CX82310_MTU 1514 | ||
56 | #define CMD_EP 0x01 | ||
57 | |||
58 | /* | ||
59 | * execute control command | ||
60 | * - optionally send some data (command parameters) | ||
61 | * - optionally wait for the reply | ||
62 | * - optionally read some data from the reply | ||
63 | */ | ||
64 | static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply, | ||
65 | u8 *wdata, int wlen, u8 *rdata, int rlen) | ||
66 | { | ||
67 | int actual_len, retries, ret; | ||
68 | struct usb_device *udev = dev->udev; | ||
69 | u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL); | ||
70 | |||
71 | if (!buf) | ||
72 | return -ENOMEM; | ||
73 | |||
74 | /* create command packet */ | ||
75 | buf[0] = cmd; | ||
76 | if (wdata) | ||
77 | memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4)); | ||
78 | |||
79 | /* send command packet */ | ||
80 | ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf, | ||
81 | CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT); | ||
82 | if (ret < 0) { | ||
83 | dev_err(&dev->udev->dev, "send command %#x: error %d\n", | ||
84 | cmd, ret); | ||
85 | goto end; | ||
86 | } | ||
87 | |||
88 | if (reply) { | ||
89 | /* wait for reply, retry if it's empty */ | ||
90 | for (retries = 0; retries < CMD_REPLY_RETRY; retries++) { | ||
91 | ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP), | ||
92 | buf, CMD_PACKET_SIZE, &actual_len, | ||
93 | CMD_TIMEOUT); | ||
94 | if (ret < 0) { | ||
95 | dev_err(&dev->udev->dev, | ||
96 | "reply receive error %d\n", ret); | ||
97 | goto end; | ||
98 | } | ||
99 | if (actual_len > 0) | ||
100 | break; | ||
101 | } | ||
102 | if (actual_len == 0) { | ||
103 | dev_err(&dev->udev->dev, "no reply to command %#x\n", | ||
104 | cmd); | ||
105 | ret = -EIO; | ||
106 | goto end; | ||
107 | } | ||
108 | if (buf[0] != cmd) { | ||
109 | dev_err(&dev->udev->dev, | ||
110 | "got reply to command %#x, expected: %#x\n", | ||
111 | buf[0], cmd); | ||
112 | ret = -EIO; | ||
113 | goto end; | ||
114 | } | ||
115 | if (buf[1] != STATUS_SUCCESS) { | ||
116 | dev_err(&dev->udev->dev, "command %#x failed: %#x\n", | ||
117 | cmd, buf[1]); | ||
118 | ret = -EIO; | ||
119 | goto end; | ||
120 | } | ||
121 | if (rdata) | ||
122 | memcpy(rdata, buf + 4, | ||
123 | min_t(int, rlen, CMD_PACKET_SIZE - 4)); | ||
124 | } | ||
125 | end: | ||
126 | kfree(buf); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | #define partial_len data[0] /* length of partial packet data */ | ||
131 | #define partial_rem data[1] /* remaining (missing) data length */ | ||
132 | #define partial_data data[2] /* partial packet data */ | ||
133 | |||
134 | static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf) | ||
135 | { | ||
136 | int ret; | ||
137 | char buf[15]; | ||
138 | struct usb_device *udev = dev->udev; | ||
139 | |||
140 | /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */ | ||
141 | if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0 | ||
142 | && strcmp(buf, "USB NET CARD")) { | ||
143 | dev_info(&udev->dev, "ignoring: probably an ADSL modem\n"); | ||
144 | return -ENODEV; | ||
145 | } | ||
146 | |||
147 | ret = usbnet_get_endpoints(dev, intf); | ||
148 | if (ret) | ||
149 | return ret; | ||
150 | |||
151 | /* | ||
152 | * this must not include ethernet header as the device can send partial | ||
153 | * packets with no header (and sometimes even empty URBs) | ||
154 | */ | ||
155 | dev->net->hard_header_len = 0; | ||
156 | /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */ | ||
157 | dev->hard_mtu = CX82310_MTU + 2; | ||
158 | /* we can receive URBs up to 4KB from the device */ | ||
159 | dev->rx_urb_size = 4096; | ||
160 | |||
161 | dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL); | ||
162 | if (!dev->partial_data) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | /* enable ethernet mode (?) */ | ||
166 | ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0); | ||
167 | if (ret) { | ||
168 | dev_err(&udev->dev, "unable to enable ethernet mode: %d\n", | ||
169 | ret); | ||
170 | goto err; | ||
171 | } | ||
172 | |||
173 | /* get the MAC address */ | ||
174 | ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0, | ||
175 | dev->net->dev_addr, ETH_ALEN); | ||
176 | if (ret) { | ||
177 | dev_err(&udev->dev, "unable to read MAC address: %d\n", ret); | ||
178 | goto err; | ||
179 | } | ||
180 | |||
181 | /* start (does not seem to have any effect?) */ | ||
182 | ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0); | ||
183 | if (ret) | ||
184 | goto err; | ||
185 | |||
186 | return 0; | ||
187 | err: | ||
188 | kfree((void *)dev->partial_data); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
193 | { | ||
194 | kfree((void *)dev->partial_data); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte | ||
199 | * packet length at the beginning. | ||
200 | * The last packet might be incomplete (when it crosses the 4KB URB size), | ||
201 | * continuing in the next skb (without any headers). | ||
202 | * If a packet has odd length, there is one extra byte at the end (before next | ||
203 | * packet or at the end of the URB). | ||
204 | */ | ||
205 | static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
206 | { | ||
207 | int len; | ||
208 | struct sk_buff *skb2; | ||
209 | |||
210 | /* | ||
211 | * If the last skb ended with an incomplete packet, this skb contains | ||
212 | * end of that packet at the beginning. | ||
213 | */ | ||
214 | if (dev->partial_rem) { | ||
215 | len = dev->partial_len + dev->partial_rem; | ||
216 | skb2 = alloc_skb(len, GFP_ATOMIC); | ||
217 | if (!skb2) | ||
218 | return 0; | ||
219 | skb_put(skb2, len); | ||
220 | memcpy(skb2->data, (void *)dev->partial_data, | ||
221 | dev->partial_len); | ||
222 | memcpy(skb2->data + dev->partial_len, skb->data, | ||
223 | dev->partial_rem); | ||
224 | usbnet_skb_return(dev, skb2); | ||
225 | skb_pull(skb, (dev->partial_rem + 1) & ~1); | ||
226 | dev->partial_rem = 0; | ||
227 | if (skb->len < 2) | ||
228 | return 1; | ||
229 | } | ||
230 | |||
231 | /* a skb can contain multiple packets */ | ||
232 | while (skb->len > 1) { | ||
233 | /* first two bytes are packet length */ | ||
234 | len = skb->data[0] | (skb->data[1] << 8); | ||
235 | skb_pull(skb, 2); | ||
236 | |||
237 | /* if last packet in the skb, let usbnet to process it */ | ||
238 | if (len == skb->len || len + 1 == skb->len) { | ||
239 | skb_trim(skb, len); | ||
240 | break; | ||
241 | } | ||
242 | |||
243 | if (len > CX82310_MTU) { | ||
244 | dev_err(&dev->udev->dev, "RX packet too long: %d B\n", | ||
245 | len); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* incomplete packet, save it for the next skb */ | ||
250 | if (len > skb->len) { | ||
251 | dev->partial_len = skb->len; | ||
252 | dev->partial_rem = len - skb->len; | ||
253 | memcpy((void *)dev->partial_data, skb->data, | ||
254 | dev->partial_len); | ||
255 | skb_pull(skb, skb->len); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | skb2 = alloc_skb(len, GFP_ATOMIC); | ||
260 | if (!skb2) | ||
261 | return 0; | ||
262 | skb_put(skb2, len); | ||
263 | memcpy(skb2->data, skb->data, len); | ||
264 | /* process the packet */ | ||
265 | usbnet_skb_return(dev, skb2); | ||
266 | |||
267 | skb_pull(skb, (len + 1) & ~1); | ||
268 | } | ||
269 | |||
270 | /* let usbnet process the last packet */ | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | /* TX is easy, just add 2 bytes of length at the beginning */ | ||
275 | static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | ||
276 | gfp_t flags) | ||
277 | { | ||
278 | int len = skb->len; | ||
279 | |||
280 | if (skb_headroom(skb) < 2) { | ||
281 | struct sk_buff *skb2 = skb_copy_expand(skb, 2, 0, flags); | ||
282 | dev_kfree_skb_any(skb); | ||
283 | skb = skb2; | ||
284 | if (!skb) | ||
285 | return NULL; | ||
286 | } | ||
287 | skb_push(skb, 2); | ||
288 | |||
289 | skb->data[0] = len; | ||
290 | skb->data[1] = len >> 8; | ||
291 | |||
292 | return skb; | ||
293 | } | ||
294 | |||
295 | |||
296 | static const struct driver_info cx82310_info = { | ||
297 | .description = "Conexant CX82310 USB ethernet", | ||
298 | .flags = FLAG_ETHER, | ||
299 | .bind = cx82310_bind, | ||
300 | .unbind = cx82310_unbind, | ||
301 | .rx_fixup = cx82310_rx_fixup, | ||
302 | .tx_fixup = cx82310_tx_fixup, | ||
303 | }; | ||
304 | |||
305 | #define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \ | ||
306 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
307 | USB_DEVICE_ID_MATCH_DEV_INFO, \ | ||
308 | .idVendor = (vend), \ | ||
309 | .idProduct = (prod), \ | ||
310 | .bDeviceClass = (cl), \ | ||
311 | .bDeviceSubClass = (sc), \ | ||
312 | .bDeviceProtocol = (pr) | ||
313 | |||
314 | static const struct usb_device_id products[] = { | ||
315 | { | ||
316 | USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0), | ||
317 | .driver_info = (unsigned long) &cx82310_info | ||
318 | }, | ||
319 | { }, | ||
320 | }; | ||
321 | MODULE_DEVICE_TABLE(usb, products); | ||
322 | |||
323 | static struct usb_driver cx82310_driver = { | ||
324 | .name = "cx82310_eth", | ||
325 | .id_table = products, | ||
326 | .probe = usbnet_probe, | ||
327 | .disconnect = usbnet_disconnect, | ||
328 | .suspend = usbnet_suspend, | ||
329 | .resume = usbnet_resume, | ||
330 | }; | ||
331 | |||
332 | static int __init cx82310_init(void) | ||
333 | { | ||
334 | return usb_register(&cx82310_driver); | ||
335 | } | ||
336 | module_init(cx82310_init); | ||
337 | |||
338 | static void __exit cx82310_exit(void) | ||
339 | { | ||
340 | usb_deregister(&cx82310_driver); | ||
341 | } | ||
342 | module_exit(cx82310_exit); | ||
343 | |||
344 | MODULE_AUTHOR("Ondrej Zary"); | ||
345 | MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver"); | ||
346 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 02b622e3b9fb..1d93133e9b74 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c | |||
@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb) | |||
599 | 599 | ||
600 | static int dm9601_link_reset(struct usbnet *dev) | 600 | static int dm9601_link_reset(struct usbnet *dev) |
601 | { | 601 | { |
602 | struct ethtool_cmd ecmd; | 602 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
603 | 603 | ||
604 | mii_check_media(&dev->mii, 1, 1); | 604 | mii_check_media(&dev->mii, 1, 1); |
605 | mii_ethtool_gset(&dev->mii, &ecmd); | 605 | mii_ethtool_gset(&dev->mii, &ecmd); |
606 | 606 | ||
607 | netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", | 607 | netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n", |
608 | ecmd.speed, ecmd.duplex); | 608 | ethtool_cmd_speed(&ecmd), ecmd.duplex); |
609 | 609 | ||
610 | return 0; | 610 | return 0; |
611 | } | 611 | } |
@@ -651,6 +651,10 @@ static const struct usb_device_id products[] = { | |||
651 | .driver_info = (unsigned long)&dm9601_info, | 651 | .driver_info = (unsigned long)&dm9601_info, |
652 | }, | 652 | }, |
653 | { | 653 | { |
654 | USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */ | ||
655 | .driver_info = (unsigned long)&dm9601_info, | ||
656 | }, | ||
657 | { | ||
654 | USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ | 658 | USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ |
655 | .driver_info = (unsigned long)&dm9601_info, | 659 | .driver_info = (unsigned long)&dm9601_info, |
656 | }, | 660 | }, |
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index dcd57c37ef73..c4cfd1dea881 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c | |||
@@ -193,7 +193,7 @@ static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) | |||
193 | 193 | ||
194 | static const struct driver_info genelink_info = { | 194 | static const struct driver_info genelink_info = { |
195 | .description = "Genesys GeneLink", | 195 | .description = "Genesys GeneLink", |
196 | .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, | 196 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT, |
197 | .bind = genelink_bind, | 197 | .bind = genelink_bind, |
198 | .rx_fixup = genelink_rx_fixup, | 198 | .rx_fixup = genelink_rx_fixup, |
199 | .tx_fixup = genelink_tx_fixup, | 199 | .tx_fixup = genelink_tx_fixup, |
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 1cd752f9a6e1..304fe78ff60e 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c | |||
@@ -324,7 +324,7 @@ struct hso_device { | |||
324 | /* Prototypes */ | 324 | /* Prototypes */ |
325 | /*****************************************************************************/ | 325 | /*****************************************************************************/ |
326 | /* Serial driver functions */ | 326 | /* Serial driver functions */ |
327 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | 327 | static int hso_serial_tiocmset(struct tty_struct *tty, |
328 | unsigned int set, unsigned int clear); | 328 | unsigned int set, unsigned int clear); |
329 | static void ctrl_callback(struct urb *urb); | 329 | static void ctrl_callback(struct urb *urb); |
330 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); | 330 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); |
@@ -843,16 +843,7 @@ static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, | |||
843 | return NETDEV_TX_OK; | 843 | return NETDEV_TX_OK; |
844 | } | 844 | } |
845 | 845 | ||
846 | static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | ||
847 | { | ||
848 | struct hso_net *odev = netdev_priv(net); | ||
849 | |||
850 | strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN); | ||
851 | usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info); | ||
852 | } | ||
853 | |||
854 | static const struct ethtool_ops ops = { | 846 | static const struct ethtool_ops ops = { |
855 | .get_drvinfo = hso_get_drvinfo, | ||
856 | .get_link = ethtool_op_get_link | 847 | .get_link = ethtool_op_get_link |
857 | }; | 848 | }; |
858 | 849 | ||
@@ -967,10 +958,6 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, | |||
967 | /* Packet is complete. Inject into stack. */ | 958 | /* Packet is complete. Inject into stack. */ |
968 | /* We have IP packet here */ | 959 | /* We have IP packet here */ |
969 | odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); | 960 | odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); |
970 | /* don't check it */ | ||
971 | odev->skb_rx_buf->ip_summed = | ||
972 | CHECKSUM_UNNECESSARY; | ||
973 | |||
974 | skb_reset_mac_header(odev->skb_rx_buf); | 961 | skb_reset_mac_header(odev->skb_rx_buf); |
975 | 962 | ||
976 | /* Ship it off to the kernel */ | 963 | /* Ship it off to the kernel */ |
@@ -1010,6 +997,18 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, | |||
1010 | } | 997 | } |
1011 | } | 998 | } |
1012 | 999 | ||
1000 | static void fix_crc_bug(struct urb *urb, __le16 max_packet_size) | ||
1001 | { | ||
1002 | static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; | ||
1003 | u32 rest = urb->actual_length % le16_to_cpu(max_packet_size); | ||
1004 | |||
1005 | if (((rest == 5) || (rest == 6)) && | ||
1006 | !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4, | ||
1007 | crc_check, 4)) { | ||
1008 | urb->actual_length -= 4; | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1013 | /* Moving data from usb to kernel (in interrupt state) */ | 1012 | /* Moving data from usb to kernel (in interrupt state) */ |
1014 | static void read_bulk_callback(struct urb *urb) | 1013 | static void read_bulk_callback(struct urb *urb) |
1015 | { | 1014 | { |
@@ -1038,17 +1037,8 @@ static void read_bulk_callback(struct urb *urb) | |||
1038 | return; | 1037 | return; |
1039 | } | 1038 | } |
1040 | 1039 | ||
1041 | if (odev->parent->port_spec & HSO_INFO_CRC_BUG) { | 1040 | if (odev->parent->port_spec & HSO_INFO_CRC_BUG) |
1042 | u32 rest; | 1041 | fix_crc_bug(urb, odev->in_endp->wMaxPacketSize); |
1043 | u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; | ||
1044 | rest = urb->actual_length % | ||
1045 | le16_to_cpu(odev->in_endp->wMaxPacketSize); | ||
1046 | if (((rest == 5) || (rest == 6)) && | ||
1047 | !memcmp(((u8 *) urb->transfer_buffer) + | ||
1048 | urb->actual_length - 4, crc_check, 4)) { | ||
1049 | urb->actual_length -= 4; | ||
1050 | } | ||
1051 | } | ||
1052 | 1042 | ||
1053 | /* do we even have a packet? */ | 1043 | /* do we even have a packet? */ |
1054 | if (urb->actual_length) { | 1044 | if (urb->actual_length) { |
@@ -1240,18 +1230,8 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) | |||
1240 | return; | 1230 | return; |
1241 | 1231 | ||
1242 | if (status == 0) { | 1232 | if (status == 0) { |
1243 | if (serial->parent->port_spec & HSO_INFO_CRC_BUG) { | 1233 | if (serial->parent->port_spec & HSO_INFO_CRC_BUG) |
1244 | u32 rest; | 1234 | fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); |
1245 | u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; | ||
1246 | rest = | ||
1247 | urb->actual_length % | ||
1248 | le16_to_cpu(serial->in_endp->wMaxPacketSize); | ||
1249 | if (((rest == 5) || (rest == 6)) && | ||
1250 | !memcmp(((u8 *) urb->transfer_buffer) + | ||
1251 | urb->actual_length - 4, crc_check, 4)) { | ||
1252 | urb->actual_length -= 4; | ||
1253 | } | ||
1254 | } | ||
1255 | /* Valid data, handle RX data */ | 1235 | /* Valid data, handle RX data */ |
1256 | spin_lock(&serial->serial_lock); | 1236 | spin_lock(&serial->serial_lock); |
1257 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; | 1237 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; |
@@ -1355,7 +1335,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |||
1355 | 1335 | ||
1356 | /* done */ | 1336 | /* done */ |
1357 | if (result) | 1337 | if (result) |
1358 | hso_serial_tiocmset(tty, NULL, TIOCM_RTS | TIOCM_DTR, 0); | 1338 | hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0); |
1359 | err_out: | 1339 | err_out: |
1360 | mutex_unlock(&serial->parent->mutex); | 1340 | mutex_unlock(&serial->parent->mutex); |
1361 | return result; | 1341 | return result; |
@@ -1645,11 +1625,11 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) | |||
1645 | * NB: both 1->0 and 0->1 transitions are counted except for | 1625 | * NB: both 1->0 and 0->1 transitions are counted except for |
1646 | * RI where only 0->1 is counted. | 1626 | * RI where only 0->1 is counted. |
1647 | */ | 1627 | */ |
1648 | static int hso_get_count(struct hso_serial *serial, | 1628 | static int hso_get_count(struct tty_struct *tty, |
1649 | struct serial_icounter_struct __user *icnt) | 1629 | struct serial_icounter_struct *icount) |
1650 | { | 1630 | { |
1651 | struct serial_icounter_struct icount; | ||
1652 | struct uart_icount cnow; | 1631 | struct uart_icount cnow; |
1632 | struct hso_serial *serial = get_serial_by_tty(tty); | ||
1653 | struct hso_tiocmget *tiocmget = serial->tiocmget; | 1633 | struct hso_tiocmget *tiocmget = serial->tiocmget; |
1654 | 1634 | ||
1655 | memset(&icount, 0, sizeof(struct serial_icounter_struct)); | 1635 | memset(&icount, 0, sizeof(struct serial_icounter_struct)); |
@@ -1660,23 +1640,23 @@ static int hso_get_count(struct hso_serial *serial, | |||
1660 | memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); | 1640 | memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); |
1661 | spin_unlock_irq(&serial->serial_lock); | 1641 | spin_unlock_irq(&serial->serial_lock); |
1662 | 1642 | ||
1663 | icount.cts = cnow.cts; | 1643 | icount->cts = cnow.cts; |
1664 | icount.dsr = cnow.dsr; | 1644 | icount->dsr = cnow.dsr; |
1665 | icount.rng = cnow.rng; | 1645 | icount->rng = cnow.rng; |
1666 | icount.dcd = cnow.dcd; | 1646 | icount->dcd = cnow.dcd; |
1667 | icount.rx = cnow.rx; | 1647 | icount->rx = cnow.rx; |
1668 | icount.tx = cnow.tx; | 1648 | icount->tx = cnow.tx; |
1669 | icount.frame = cnow.frame; | 1649 | icount->frame = cnow.frame; |
1670 | icount.overrun = cnow.overrun; | 1650 | icount->overrun = cnow.overrun; |
1671 | icount.parity = cnow.parity; | 1651 | icount->parity = cnow.parity; |
1672 | icount.brk = cnow.brk; | 1652 | icount->brk = cnow.brk; |
1673 | icount.buf_overrun = cnow.buf_overrun; | 1653 | icount->buf_overrun = cnow.buf_overrun; |
1674 | 1654 | ||
1675 | return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; | 1655 | return 0; |
1676 | } | 1656 | } |
1677 | 1657 | ||
1678 | 1658 | ||
1679 | static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) | 1659 | static int hso_serial_tiocmget(struct tty_struct *tty) |
1680 | { | 1660 | { |
1681 | int retval; | 1661 | int retval; |
1682 | struct hso_serial *serial = get_serial_by_tty(tty); | 1662 | struct hso_serial *serial = get_serial_by_tty(tty); |
@@ -1707,7 +1687,7 @@ static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file) | |||
1707 | return retval; | 1687 | return retval; |
1708 | } | 1688 | } |
1709 | 1689 | ||
1710 | static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | 1690 | static int hso_serial_tiocmset(struct tty_struct *tty, |
1711 | unsigned int set, unsigned int clear) | 1691 | unsigned int set, unsigned int clear) |
1712 | { | 1692 | { |
1713 | int val = 0; | 1693 | int val = 0; |
@@ -1750,11 +1730,10 @@ static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file, | |||
1750 | USB_CTRL_SET_TIMEOUT); | 1730 | USB_CTRL_SET_TIMEOUT); |
1751 | } | 1731 | } |
1752 | 1732 | ||
1753 | static int hso_serial_ioctl(struct tty_struct *tty, struct file *file, | 1733 | static int hso_serial_ioctl(struct tty_struct *tty, |
1754 | unsigned int cmd, unsigned long arg) | 1734 | unsigned int cmd, unsigned long arg) |
1755 | { | 1735 | { |
1756 | struct hso_serial *serial = get_serial_by_tty(tty); | 1736 | struct hso_serial *serial = get_serial_by_tty(tty); |
1757 | void __user *uarg = (void __user *)arg; | ||
1758 | int ret = 0; | 1737 | int ret = 0; |
1759 | D4("IOCTL cmd: %d, arg: %ld", cmd, arg); | 1738 | D4("IOCTL cmd: %d, arg: %ld", cmd, arg); |
1760 | 1739 | ||
@@ -1764,10 +1743,6 @@ static int hso_serial_ioctl(struct tty_struct *tty, struct file *file, | |||
1764 | case TIOCMIWAIT: | 1743 | case TIOCMIWAIT: |
1765 | ret = hso_wait_modem_status(serial, arg); | 1744 | ret = hso_wait_modem_status(serial, arg); |
1766 | break; | 1745 | break; |
1767 | |||
1768 | case TIOCGICOUNT: | ||
1769 | ret = hso_get_count(serial, uarg); | ||
1770 | break; | ||
1771 | default: | 1746 | default: |
1772 | ret = -ENOIOCTLCMD; | 1747 | ret = -ENOIOCTLCMD; |
1773 | break; | 1748 | break; |
@@ -2446,10 +2421,8 @@ static void hso_free_net_device(struct hso_device *hso_dev) | |||
2446 | 2421 | ||
2447 | remove_net_device(hso_net->parent); | 2422 | remove_net_device(hso_net->parent); |
2448 | 2423 | ||
2449 | if (hso_net->net) { | 2424 | if (hso_net->net) |
2450 | unregister_netdev(hso_net->net); | 2425 | unregister_netdev(hso_net->net); |
2451 | free_netdev(hso_net->net); | ||
2452 | } | ||
2453 | 2426 | ||
2454 | /* start freeing */ | 2427 | /* start freeing */ |
2455 | for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { | 2428 | for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { |
@@ -2461,6 +2434,9 @@ static void hso_free_net_device(struct hso_device *hso_dev) | |||
2461 | kfree(hso_net->mux_bulk_tx_buf); | 2434 | kfree(hso_net->mux_bulk_tx_buf); |
2462 | hso_net->mux_bulk_tx_buf = NULL; | 2435 | hso_net->mux_bulk_tx_buf = NULL; |
2463 | 2436 | ||
2437 | if (hso_net->net) | ||
2438 | free_netdev(hso_net->net); | ||
2439 | |||
2464 | kfree(hso_dev); | 2440 | kfree(hso_dev); |
2465 | } | 2441 | } |
2466 | 2442 | ||
@@ -2653,15 +2629,15 @@ exit: | |||
2653 | 2629 | ||
2654 | static void hso_free_tiomget(struct hso_serial *serial) | 2630 | static void hso_free_tiomget(struct hso_serial *serial) |
2655 | { | 2631 | { |
2656 | struct hso_tiocmget *tiocmget = serial->tiocmget; | 2632 | struct hso_tiocmget *tiocmget; |
2633 | if (!serial) | ||
2634 | return; | ||
2635 | tiocmget = serial->tiocmget; | ||
2657 | if (tiocmget) { | 2636 | if (tiocmget) { |
2658 | if (tiocmget->urb) { | 2637 | usb_free_urb(tiocmget->urb); |
2659 | usb_free_urb(tiocmget->urb); | 2638 | tiocmget->urb = NULL; |
2660 | tiocmget->urb = NULL; | ||
2661 | } | ||
2662 | serial->tiocmget = NULL; | 2639 | serial->tiocmget = NULL; |
2663 | kfree(tiocmget); | 2640 | kfree(tiocmget); |
2664 | |||
2665 | } | 2641 | } |
2666 | } | 2642 | } |
2667 | 2643 | ||
@@ -3007,12 +2983,14 @@ static int hso_probe(struct usb_interface *interface, | |||
3007 | 2983 | ||
3008 | case HSO_INTF_BULK: | 2984 | case HSO_INTF_BULK: |
3009 | /* It's a regular bulk interface */ | 2985 | /* It's a regular bulk interface */ |
3010 | if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) && | 2986 | if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { |
3011 | !disable_net) | 2987 | if (!disable_net) |
3012 | hso_dev = hso_create_net_device(interface, port_spec); | 2988 | hso_dev = |
3013 | else | 2989 | hso_create_net_device(interface, port_spec); |
2990 | } else { | ||
3014 | hso_dev = | 2991 | hso_dev = |
3015 | hso_create_bulk_serial_device(interface, port_spec); | 2992 | hso_create_bulk_serial_device(interface, port_spec); |
2993 | } | ||
3016 | if (!hso_dev) | 2994 | if (!hso_dev) |
3017 | goto exit; | 2995 | goto exit; |
3018 | break; | 2996 | break; |
@@ -3300,6 +3278,7 @@ static const struct tty_operations hso_serial_ops = { | |||
3300 | .chars_in_buffer = hso_serial_chars_in_buffer, | 3278 | .chars_in_buffer = hso_serial_chars_in_buffer, |
3301 | .tiocmget = hso_serial_tiocmget, | 3279 | .tiocmget = hso_serial_tiocmget, |
3302 | .tiocmset = hso_serial_tiocmset, | 3280 | .tiocmset = hso_serial_tiocmset, |
3281 | .get_icount = hso_get_count, | ||
3303 | .unthrottle = hso_unthrottle | 3282 | .unthrottle = hso_unthrottle |
3304 | }; | 3283 | }; |
3305 | 3284 | ||
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index b2bcf99e6f08..81126ff85e05 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #define IPHETH_USBINTF_PROTO 1 | 65 | #define IPHETH_USBINTF_PROTO 1 |
66 | 66 | ||
67 | #define IPHETH_BUF_SIZE 1516 | 67 | #define IPHETH_BUF_SIZE 1516 |
68 | #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ | ||
68 | #define IPHETH_TX_TIMEOUT (5 * HZ) | 69 | #define IPHETH_TX_TIMEOUT (5 * HZ) |
69 | 70 | ||
70 | #define IPHETH_INTFNUM 2 | 71 | #define IPHETH_INTFNUM 2 |
@@ -202,18 +203,21 @@ static void ipheth_rcvbulk_callback(struct urb *urb) | |||
202 | return; | 203 | return; |
203 | } | 204 | } |
204 | 205 | ||
205 | len = urb->actual_length; | 206 | if (urb->actual_length <= IPHETH_IP_ALIGN) { |
206 | buf = urb->transfer_buffer; | 207 | dev->net->stats.rx_length_errors++; |
208 | return; | ||
209 | } | ||
210 | len = urb->actual_length - IPHETH_IP_ALIGN; | ||
211 | buf = urb->transfer_buffer + IPHETH_IP_ALIGN; | ||
207 | 212 | ||
208 | skb = dev_alloc_skb(NET_IP_ALIGN + len); | 213 | skb = dev_alloc_skb(len); |
209 | if (!skb) { | 214 | if (!skb) { |
210 | err("%s: dev_alloc_skb: -ENOMEM", __func__); | 215 | err("%s: dev_alloc_skb: -ENOMEM", __func__); |
211 | dev->net->stats.rx_dropped++; | 216 | dev->net->stats.rx_dropped++; |
212 | return; | 217 | return; |
213 | } | 218 | } |
214 | 219 | ||
215 | skb_reserve(skb, NET_IP_ALIGN); | 220 | memcpy(skb_put(skb, len), buf, len); |
216 | memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN); | ||
217 | skb->dev = dev->net; | 221 | skb->dev = dev->net; |
218 | skb->protocol = eth_type_trans(skb, dev->net); | 222 | skb->protocol = eth_type_trans(skb, dev->net); |
219 | 223 | ||
@@ -363,7 +367,7 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net) | |||
363 | 367 | ||
364 | /* Paranoid */ | 368 | /* Paranoid */ |
365 | if (skb->len > IPHETH_BUF_SIZE) { | 369 | if (skb->len > IPHETH_BUF_SIZE) { |
366 | WARN(1, "%s: skb too large: %d bytes", __func__, skb->len); | 370 | WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); |
367 | dev->net->stats.tx_dropped++; | 371 | dev->net->stats.tx_dropped++; |
368 | dev_kfree_skb_irq(skb); | 372 | dev_kfree_skb_irq(skb); |
369 | return NETDEV_TX_OK; | 373 | return NETDEV_TX_OK; |
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c new file mode 100644 index 000000000000..a9b6c63d54e4 --- /dev/null +++ b/drivers/net/usb/kalmia.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * USB network interface driver for Samsung Kalmia based LTE USB modem like the | ||
3 | * Samsung GT-B3730 and GT-B3710. | ||
4 | * | ||
5 | * Copyright (C) 2011 Marius Bjoernstad Kotsbak <marius@kotsbak.com> | ||
6 | * | ||
7 | * Sponsored by Quicklink Video Distribution Services Ltd. | ||
8 | * | ||
9 | * Based on the cdc_eem module. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/etherdevice.h> | ||
21 | #include <linux/ctype.h> | ||
22 | #include <linux/ethtool.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <linux/mii.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/crc32.h> | ||
27 | #include <linux/usb/cdc.h> | ||
28 | #include <linux/usb/usbnet.h> | ||
29 | #include <linux/gfp.h> | ||
30 | |||
31 | /* | ||
32 | * The Samsung Kalmia based LTE USB modems have a CDC ACM port for modem control | ||
33 | * handled by the "option" module and an ethernet data port handled by this | ||
34 | * module. | ||
35 | * | ||
36 | * The stick must first be switched into modem mode by usb_modeswitch | ||
37 | * or similar tool. Then the modem gets sent two initialization packets by | ||
38 | * this module, which gives the MAC address of the device. User space can then | ||
39 | * connect the modem using AT commands through the ACM port and then use | ||
40 | * DHCP on the network interface exposed by this module. Network packets are | ||
41 | * sent to and from the modem in a proprietary format discovered after watching | ||
42 | * the behavior of the windows driver for the modem. | ||
43 | * | ||
44 | * More information about the use of the modem is available in usb_modeswitch | ||
45 | * forum and the project page: | ||
46 | * | ||
47 | * http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?t=465 | ||
48 | * https://github.com/mkotsbak/Samsung-GT-B3730-linux-driver | ||
49 | */ | ||
50 | |||
51 | /* #define DEBUG */ | ||
52 | /* #define VERBOSE */ | ||
53 | |||
54 | #define KALMIA_HEADER_LENGTH 6 | ||
55 | #define KALMIA_ALIGN_SIZE 4 | ||
56 | #define KALMIA_USB_TIMEOUT 10000 | ||
57 | |||
58 | /*-------------------------------------------------------------------------*/ | ||
59 | |||
60 | static int | ||
61 | kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len, | ||
62 | u8 *buffer, u8 expected_len) | ||
63 | { | ||
64 | int act_len; | ||
65 | int status; | ||
66 | |||
67 | netdev_dbg(dev->net, "Sending init packet"); | ||
68 | |||
69 | status = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 0x02), | ||
70 | init_msg, init_msg_len, &act_len, KALMIA_USB_TIMEOUT); | ||
71 | if (status != 0) { | ||
72 | netdev_err(dev->net, | ||
73 | "Error sending init packet. Status %i, length %i\n", | ||
74 | status, act_len); | ||
75 | return status; | ||
76 | } | ||
77 | else if (act_len != init_msg_len) { | ||
78 | netdev_err(dev->net, | ||
79 | "Did not send all of init packet. Bytes sent: %i", | ||
80 | act_len); | ||
81 | } | ||
82 | else { | ||
83 | netdev_dbg(dev->net, "Successfully sent init packet."); | ||
84 | } | ||
85 | |||
86 | status = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x81), | ||
87 | buffer, expected_len, &act_len, KALMIA_USB_TIMEOUT); | ||
88 | |||
89 | if (status != 0) | ||
90 | netdev_err(dev->net, | ||
91 | "Error receiving init result. Status %i, length %i\n", | ||
92 | status, act_len); | ||
93 | else if (act_len != expected_len) | ||
94 | netdev_err(dev->net, "Unexpected init result length: %i\n", | ||
95 | act_len); | ||
96 | |||
97 | return status; | ||
98 | } | ||
99 | |||
100 | static int | ||
101 | kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr) | ||
102 | { | ||
103 | const static char init_msg_1[] = | ||
104 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, | ||
105 | 0x00, 0x00 }; | ||
106 | const static char init_msg_2[] = | ||
107 | { 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4, | ||
108 | 0x00, 0x00 }; | ||
109 | const static int buflen = 28; | ||
110 | char *usb_buf; | ||
111 | int status; | ||
112 | |||
113 | usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL); | ||
114 | if (!usb_buf) | ||
115 | return -ENOMEM; | ||
116 | |||
117 | memcpy(usb_buf, init_msg_1, 12); | ||
118 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1) | ||
119 | / sizeof(init_msg_1[0]), usb_buf, 24); | ||
120 | if (status != 0) | ||
121 | return status; | ||
122 | |||
123 | memcpy(usb_buf, init_msg_2, 12); | ||
124 | status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2) | ||
125 | / sizeof(init_msg_2[0]), usb_buf, 28); | ||
126 | if (status != 0) | ||
127 | return status; | ||
128 | |||
129 | memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN); | ||
130 | |||
131 | kfree(usb_buf); | ||
132 | return status; | ||
133 | } | ||
134 | |||
135 | static int | ||
136 | kalmia_bind(struct usbnet *dev, struct usb_interface *intf) | ||
137 | { | ||
138 | int status; | ||
139 | u8 ethernet_addr[ETH_ALEN]; | ||
140 | |||
141 | /* Don't bind to AT command interface */ | ||
142 | if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) | ||
143 | return -EINVAL; | ||
144 | |||
145 | dev->in = usb_rcvbulkpipe(dev->udev, 0x81 & USB_ENDPOINT_NUMBER_MASK); | ||
146 | dev->out = usb_sndbulkpipe(dev->udev, 0x02 & USB_ENDPOINT_NUMBER_MASK); | ||
147 | dev->status = NULL; | ||
148 | |||
149 | dev->net->hard_header_len += KALMIA_HEADER_LENGTH; | ||
150 | dev->hard_mtu = 1400; | ||
151 | dev->rx_urb_size = dev->hard_mtu * 10; // Found as optimal after testing | ||
152 | |||
153 | status = kalmia_init_and_get_ethernet_addr(dev, ethernet_addr); | ||
154 | |||
155 | if (status < 0) { | ||
156 | usb_set_intfdata(intf, NULL); | ||
157 | usb_driver_release_interface(driver_of(intf), intf); | ||
158 | return status; | ||
159 | } | ||
160 | |||
161 | memcpy(dev->net->dev_addr, ethernet_addr, ETH_ALEN); | ||
162 | memcpy(dev->net->perm_addr, ethernet_addr, ETH_ALEN); | ||
163 | |||
164 | return status; | ||
165 | } | ||
166 | |||
167 | static struct sk_buff * | ||
168 | kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | ||
169 | { | ||
170 | struct sk_buff *skb2 = NULL; | ||
171 | u16 content_len; | ||
172 | unsigned char *header_start; | ||
173 | unsigned char ether_type_1, ether_type_2; | ||
174 | u8 remainder, padlen = 0; | ||
175 | |||
176 | if (!skb_cloned(skb)) { | ||
177 | int headroom = skb_headroom(skb); | ||
178 | int tailroom = skb_tailroom(skb); | ||
179 | |||
180 | if ((tailroom >= KALMIA_ALIGN_SIZE) && (headroom | ||
181 | >= KALMIA_HEADER_LENGTH)) | ||
182 | goto done; | ||
183 | |||
184 | if ((headroom + tailroom) > (KALMIA_HEADER_LENGTH | ||
185 | + KALMIA_ALIGN_SIZE)) { | ||
186 | skb->data = memmove(skb->head + KALMIA_HEADER_LENGTH, | ||
187 | skb->data, skb->len); | ||
188 | skb_set_tail_pointer(skb, skb->len); | ||
189 | goto done; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | skb2 = skb_copy_expand(skb, KALMIA_HEADER_LENGTH, | ||
194 | KALMIA_ALIGN_SIZE, flags); | ||
195 | if (!skb2) | ||
196 | return NULL; | ||
197 | |||
198 | dev_kfree_skb_any(skb); | ||
199 | skb = skb2; | ||
200 | |||
201 | done: | ||
202 | header_start = skb_push(skb, KALMIA_HEADER_LENGTH); | ||
203 | ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12]; | ||
204 | ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13]; | ||
205 | |||
206 | netdev_dbg(dev->net, "Sending etherType: %02x%02x", ether_type_1, | ||
207 | ether_type_2); | ||
208 | |||
209 | /* According to empiric data for data packages */ | ||
210 | header_start[0] = 0x57; | ||
211 | header_start[1] = 0x44; | ||
212 | content_len = skb->len - KALMIA_HEADER_LENGTH; | ||
213 | |||
214 | put_unaligned_le16(content_len, &header_start[2]); | ||
215 | header_start[4] = ether_type_1; | ||
216 | header_start[5] = ether_type_2; | ||
217 | |||
218 | /* Align to 4 bytes by padding with zeros */ | ||
219 | remainder = skb->len % KALMIA_ALIGN_SIZE; | ||
220 | if (remainder > 0) { | ||
221 | padlen = KALMIA_ALIGN_SIZE - remainder; | ||
222 | memset(skb_put(skb, padlen), 0, padlen); | ||
223 | } | ||
224 | |||
225 | netdev_dbg( | ||
226 | dev->net, | ||
227 | "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.", | ||
228 | content_len, padlen, header_start[0], header_start[1], | ||
229 | header_start[2], header_start[3], header_start[4], | ||
230 | header_start[5]); | ||
231 | |||
232 | return skb; | ||
233 | } | ||
234 | |||
235 | static int | ||
236 | kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
237 | { | ||
238 | /* | ||
239 | * Our task here is to strip off framing, leaving skb with one | ||
240 | * data frame for the usbnet framework code to process. | ||
241 | */ | ||
242 | const static u8 HEADER_END_OF_USB_PACKET[] = | ||
243 | { 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 }; | ||
244 | const static u8 EXPECTED_UNKNOWN_HEADER_1[] = | ||
245 | { 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 }; | ||
246 | const static u8 EXPECTED_UNKNOWN_HEADER_2[] = | ||
247 | { 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 }; | ||
248 | int i = 0; | ||
249 | |||
250 | /* incomplete header? */ | ||
251 | if (skb->len < KALMIA_HEADER_LENGTH) | ||
252 | return 0; | ||
253 | |||
254 | do { | ||
255 | struct sk_buff *skb2 = NULL; | ||
256 | u8 *header_start; | ||
257 | u16 usb_packet_length, ether_packet_length; | ||
258 | int is_last; | ||
259 | |||
260 | header_start = skb->data; | ||
261 | |||
262 | if (unlikely(header_start[0] != 0x57 || header_start[1] != 0x44)) { | ||
263 | if (!memcmp(header_start, EXPECTED_UNKNOWN_HEADER_1, | ||
264 | sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp( | ||
265 | header_start, EXPECTED_UNKNOWN_HEADER_2, | ||
266 | sizeof(EXPECTED_UNKNOWN_HEADER_2))) { | ||
267 | netdev_dbg( | ||
268 | dev->net, | ||
269 | "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | ||
270 | header_start[0], header_start[1], | ||
271 | header_start[2], header_start[3], | ||
272 | header_start[4], header_start[5], | ||
273 | skb->len - KALMIA_HEADER_LENGTH); | ||
274 | } | ||
275 | else { | ||
276 | netdev_err( | ||
277 | dev->net, | ||
278 | "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | ||
279 | header_start[0], header_start[1], | ||
280 | header_start[2], header_start[3], | ||
281 | header_start[4], header_start[5], | ||
282 | skb->len - KALMIA_HEADER_LENGTH); | ||
283 | return 0; | ||
284 | } | ||
285 | } | ||
286 | else | ||
287 | netdev_dbg( | ||
288 | dev->net, | ||
289 | "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | ||
290 | header_start[0], header_start[1], header_start[2], | ||
291 | header_start[3], header_start[4], header_start[5], | ||
292 | skb->len - KALMIA_HEADER_LENGTH); | ||
293 | |||
294 | /* subtract start header and end header */ | ||
295 | usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); | ||
296 | ether_packet_length = get_unaligned_le16(&header_start[2]); | ||
297 | skb_pull(skb, KALMIA_HEADER_LENGTH); | ||
298 | |||
299 | /* Some small packets misses end marker */ | ||
300 | if (usb_packet_length < ether_packet_length) { | ||
301 | ether_packet_length = usb_packet_length | ||
302 | + KALMIA_HEADER_LENGTH; | ||
303 | is_last = true; | ||
304 | } | ||
305 | else { | ||
306 | netdev_dbg(dev->net, "Correct package length #%i", i | ||
307 | + 1); | ||
308 | |||
309 | is_last = (memcmp(skb->data + ether_packet_length, | ||
310 | HEADER_END_OF_USB_PACKET, | ||
311 | sizeof(HEADER_END_OF_USB_PACKET)) == 0); | ||
312 | if (!is_last) { | ||
313 | header_start = skb->data + ether_packet_length; | ||
314 | netdev_dbg( | ||
315 | dev->net, | ||
316 | "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n", | ||
317 | header_start[0], header_start[1], | ||
318 | header_start[2], header_start[3], | ||
319 | header_start[4], header_start[5], | ||
320 | skb->len - KALMIA_HEADER_LENGTH); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | if (is_last) { | ||
325 | skb2 = skb; | ||
326 | } | ||
327 | else { | ||
328 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
329 | if (unlikely(!skb2)) | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | skb_trim(skb2, ether_packet_length); | ||
334 | |||
335 | if (is_last) { | ||
336 | return 1; | ||
337 | } | ||
338 | else { | ||
339 | usbnet_skb_return(dev, skb2); | ||
340 | skb_pull(skb, ether_packet_length); | ||
341 | } | ||
342 | |||
343 | i++; | ||
344 | } | ||
345 | while (skb->len); | ||
346 | |||
347 | return 1; | ||
348 | } | ||
349 | |||
350 | static const struct driver_info kalmia_info = { | ||
351 | .description = "Samsung Kalmia LTE USB dongle", | ||
352 | .flags = FLAG_WWAN, | ||
353 | .bind = kalmia_bind, | ||
354 | .rx_fixup = kalmia_rx_fixup, | ||
355 | .tx_fixup = kalmia_tx_fixup | ||
356 | }; | ||
357 | |||
358 | /*-------------------------------------------------------------------------*/ | ||
359 | |||
360 | static const struct usb_device_id products[] = { | ||
361 | /* The unswitched USB ID, to get the module auto loaded: */ | ||
362 | { USB_DEVICE(0x04e8, 0x689a) }, | ||
363 | /* The stick swithed into modem (by e.g. usb_modeswitch): */ | ||
364 | { USB_DEVICE(0x04e8, 0x6889), | ||
365 | .driver_info = (unsigned long) &kalmia_info, }, | ||
366 | { /* EMPTY == end of list */} }; | ||
367 | MODULE_DEVICE_TABLE( usb, products); | ||
368 | |||
369 | static struct usb_driver kalmia_driver = { | ||
370 | .name = "kalmia", | ||
371 | .id_table = products, | ||
372 | .probe = usbnet_probe, | ||
373 | .disconnect = usbnet_disconnect, | ||
374 | .suspend = usbnet_suspend, | ||
375 | .resume = usbnet_resume | ||
376 | }; | ||
377 | |||
378 | static int __init kalmia_init(void) | ||
379 | { | ||
380 | return usb_register(&kalmia_driver); | ||
381 | } | ||
382 | module_init( kalmia_init); | ||
383 | |||
384 | static void __exit kalmia_exit(void) | ||
385 | { | ||
386 | usb_deregister(&kalmia_driver); | ||
387 | } | ||
388 | module_exit( kalmia_exit); | ||
389 | |||
390 | MODULE_AUTHOR("Marius Bjoernstad Kotsbak <marius@kotsbak.com>"); | ||
391 | MODULE_DESCRIPTION("Samsung Kalmia USB network driver"); | ||
392 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 2b7b39cad1ce..ad0298f9b5f9 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c | |||
@@ -406,6 +406,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, | |||
406 | 406 | ||
407 | if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { | 407 | if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { |
408 | err("Firmware too big: %zu", fw->size); | 408 | err("Firmware too big: %zu", fw->size); |
409 | release_firmware(fw); | ||
409 | return -ENOSPC; | 410 | return -ENOSPC; |
410 | } | 411 | } |
411 | data_len = fw->size; | 412 | data_len = fw->size; |
@@ -759,14 +760,6 @@ static int kaweth_close(struct net_device *net) | |||
759 | return 0; | 760 | return 0; |
760 | } | 761 | } |
761 | 762 | ||
762 | static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
763 | { | ||
764 | struct kaweth_device *kaweth = netdev_priv(dev); | ||
765 | |||
766 | strlcpy(info->driver, driver_name, sizeof(info->driver)); | ||
767 | usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); | ||
768 | } | ||
769 | |||
770 | static u32 kaweth_get_link(struct net_device *dev) | 763 | static u32 kaweth_get_link(struct net_device *dev) |
771 | { | 764 | { |
772 | struct kaweth_device *kaweth = netdev_priv(dev); | 765 | struct kaweth_device *kaweth = netdev_priv(dev); |
@@ -775,7 +768,6 @@ static u32 kaweth_get_link(struct net_device *dev) | |||
775 | } | 768 | } |
776 | 769 | ||
777 | static const struct ethtool_ops ops = { | 770 | static const struct ethtool_ops ops = { |
778 | .get_drvinfo = kaweth_get_drvinfo, | ||
779 | .get_link = kaweth_get_link | 771 | .get_link = kaweth_get_link |
780 | }; | 772 | }; |
781 | 773 | ||
@@ -1229,7 +1221,7 @@ static void kaweth_disconnect(struct usb_interface *intf) | |||
1229 | 1221 | ||
1230 | usb_set_intfdata(intf, NULL); | 1222 | usb_set_intfdata(intf, NULL); |
1231 | if (!kaweth) { | 1223 | if (!kaweth) { |
1232 | dev_warn(&intf->dev, "unregistering non-existant device\n"); | 1224 | dev_warn(&intf->dev, "unregistering non-existent device\n"); |
1233 | return; | 1225 | return; |
1234 | } | 1226 | } |
1235 | netdev = kaweth->net; | 1227 | netdev = kaweth->net; |
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c new file mode 100644 index 000000000000..1d83ccfd7277 --- /dev/null +++ b/drivers/net/usb/lg-vl600.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * Ethernet interface part of the LG VL600 LTE modem (4G dongle) | ||
3 | * | ||
4 | * Copyright (C) 2011 Intel Corporation | ||
5 | * Author: Andrzej Zaborowski <balrogg@gmail.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/etherdevice.h> | ||
22 | #include <linux/ethtool.h> | ||
23 | #include <linux/mii.h> | ||
24 | #include <linux/usb.h> | ||
25 | #include <linux/usb/cdc.h> | ||
26 | #include <linux/usb/usbnet.h> | ||
27 | #include <linux/if_ether.h> | ||
28 | #include <linux/if_arp.h> | ||
29 | #include <linux/inetdevice.h> | ||
30 | |||
31 | /* | ||
32 | * The device has a CDC ACM port for modem control (it claims to be | ||
33 | * CDC ACM anyway) and a CDC Ethernet port for actual network data. | ||
34 | * It will however ignore data on both ports that is not encapsulated | ||
35 | * in a specific way, any data returned is also encapsulated the same | ||
36 | * way. The headers don't seem to follow any popular standard. | ||
37 | * | ||
38 | * This driver adds and strips these headers from the ethernet frames | ||
39 | * sent/received from the CDC Ethernet port. The proprietary header | ||
40 | * replaces the standard ethernet header in a packet so only actual | ||
41 | * ethernet frames are allowed. The headers allow some form of | ||
42 | * multiplexing by using non standard values of the .h_proto field. | ||
43 | * Windows/Mac drivers do send a couple of such frames to the device | ||
44 | * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what | ||
45 | * seems to be) a flag in the .dummy_flags. This doesn't seem necessary | ||
46 | * for modem operation but can possibly be used for GPS or other funcitons. | ||
47 | */ | ||
48 | |||
49 | struct vl600_frame_hdr { | ||
50 | __le32 len; | ||
51 | __le32 serial; | ||
52 | __le32 pkt_cnt; | ||
53 | __le32 dummy_flags; | ||
54 | __le32 dummy; | ||
55 | __le32 magic; | ||
56 | } __attribute__((packed)); | ||
57 | |||
58 | struct vl600_pkt_hdr { | ||
59 | __le32 dummy[2]; | ||
60 | __le32 len; | ||
61 | __be16 h_proto; | ||
62 | } __attribute__((packed)); | ||
63 | |||
64 | struct vl600_state { | ||
65 | struct sk_buff *current_rx_buf; | ||
66 | }; | ||
67 | |||
68 | static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) | ||
69 | { | ||
70 | int ret; | ||
71 | struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL); | ||
72 | |||
73 | if (!s) | ||
74 | return -ENOMEM; | ||
75 | |||
76 | ret = usbnet_cdc_bind(dev, intf); | ||
77 | if (ret) { | ||
78 | kfree(s); | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | dev->driver_priv = s; | ||
83 | |||
84 | /* ARP packets don't go through, but they're also of no use. The | ||
85 | * subnet has only two hosts anyway: us and the gateway / DHCP | ||
86 | * server (probably simulated by modem firmware or network operator) | ||
87 | * whose address changes everytime we connect to the intarwebz and | ||
88 | * who doesn't bother answering ARP requests either. So hardware | ||
89 | * addresses have no meaning, the destination and the source of every | ||
90 | * packet depend only on whether it is on the IN or OUT endpoint. */ | ||
91 | dev->net->flags |= IFF_NOARP; | ||
92 | |||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf) | ||
97 | { | ||
98 | struct vl600_state *s = dev->driver_priv; | ||
99 | |||
100 | if (s->current_rx_buf) | ||
101 | dev_kfree_skb(s->current_rx_buf); | ||
102 | |||
103 | kfree(s); | ||
104 | |||
105 | return usbnet_cdc_unbind(dev, intf); | ||
106 | } | ||
107 | |||
108 | static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | ||
109 | { | ||
110 | struct vl600_frame_hdr *frame; | ||
111 | struct vl600_pkt_hdr *packet; | ||
112 | struct ethhdr *ethhdr; | ||
113 | int packet_len, count; | ||
114 | struct sk_buff *buf = skb; | ||
115 | struct sk_buff *clone; | ||
116 | struct vl600_state *s = dev->driver_priv; | ||
117 | |||
118 | /* Frame lengths are generally 4B multiplies but every couple of | ||
119 | * hours there's an odd number of bytes sized yet correct frame, | ||
120 | * so don't require this. */ | ||
121 | |||
122 | /* Allow a packet (or multiple packets batched together) to be | ||
123 | * split across many frames. We don't allow a new batch to | ||
124 | * begin in the same frame another one is ending however, and no | ||
125 | * leading or trailing pad bytes. */ | ||
126 | if (s->current_rx_buf) { | ||
127 | frame = (struct vl600_frame_hdr *) s->current_rx_buf->data; | ||
128 | if (skb->len + s->current_rx_buf->len > | ||
129 | le32_to_cpup(&frame->len)) { | ||
130 | netif_err(dev, ifup, dev->net, "Fragment too long\n"); | ||
131 | dev->net->stats.rx_length_errors++; | ||
132 | goto error; | ||
133 | } | ||
134 | |||
135 | buf = s->current_rx_buf; | ||
136 | memcpy(skb_put(buf, skb->len), skb->data, skb->len); | ||
137 | } else if (skb->len < 4) { | ||
138 | netif_err(dev, ifup, dev->net, "Frame too short\n"); | ||
139 | dev->net->stats.rx_length_errors++; | ||
140 | goto error; | ||
141 | } | ||
142 | |||
143 | frame = (struct vl600_frame_hdr *) buf->data; | ||
144 | /* NOTE: Should check that frame->magic == 0x53544448? | ||
145 | * Otherwise if we receive garbage at the beginning of the frame | ||
146 | * we may end up allocating a huge buffer and saving all the | ||
147 | * future incoming data into it. */ | ||
148 | |||
149 | if (buf->len < sizeof(*frame) || | ||
150 | buf->len != le32_to_cpup(&frame->len)) { | ||
151 | /* Save this fragment for later assembly */ | ||
152 | if (s->current_rx_buf) | ||
153 | return 0; | ||
154 | |||
155 | s->current_rx_buf = skb_copy_expand(skb, 0, | ||
156 | le32_to_cpup(&frame->len), GFP_ATOMIC); | ||
157 | if (!s->current_rx_buf) { | ||
158 | netif_err(dev, ifup, dev->net, "Reserving %i bytes " | ||
159 | "for packet assembly failed.\n", | ||
160 | le32_to_cpup(&frame->len)); | ||
161 | dev->net->stats.rx_errors++; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | count = le32_to_cpup(&frame->pkt_cnt); | ||
168 | |||
169 | skb_pull(buf, sizeof(*frame)); | ||
170 | |||
171 | while (count--) { | ||
172 | if (buf->len < sizeof(*packet)) { | ||
173 | netif_err(dev, ifup, dev->net, "Packet too short\n"); | ||
174 | goto error; | ||
175 | } | ||
176 | |||
177 | packet = (struct vl600_pkt_hdr *) buf->data; | ||
178 | packet_len = sizeof(*packet) + le32_to_cpup(&packet->len); | ||
179 | if (packet_len > buf->len) { | ||
180 | netif_err(dev, ifup, dev->net, | ||
181 | "Bad packet length stored in header\n"); | ||
182 | goto error; | ||
183 | } | ||
184 | |||
185 | /* Packet header is same size as the ethernet header | ||
186 | * (sizeof(*packet) == sizeof(*ethhdr)), additionally | ||
187 | * the h_proto field is in the same place so we just leave it | ||
188 | * alone and fill in the remaining fields. | ||
189 | */ | ||
190 | ethhdr = (struct ethhdr *) skb->data; | ||
191 | if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP && | ||
192 | buf->len > 0x26) { | ||
193 | /* Copy the addresses from packet contents */ | ||
194 | memcpy(ethhdr->h_source, | ||
195 | &buf->data[sizeof(*ethhdr) + 0x8], | ||
196 | ETH_ALEN); | ||
197 | memcpy(ethhdr->h_dest, | ||
198 | &buf->data[sizeof(*ethhdr) + 0x12], | ||
199 | ETH_ALEN); | ||
200 | } else { | ||
201 | memset(ethhdr->h_source, 0, ETH_ALEN); | ||
202 | memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); | ||
203 | } | ||
204 | |||
205 | if (count) { | ||
206 | /* Not the last packet in this batch */ | ||
207 | clone = skb_clone(buf, GFP_ATOMIC); | ||
208 | if (!clone) | ||
209 | goto error; | ||
210 | |||
211 | skb_trim(clone, packet_len); | ||
212 | usbnet_skb_return(dev, clone); | ||
213 | |||
214 | skb_pull(buf, (packet_len + 3) & ~3); | ||
215 | } else { | ||
216 | skb_trim(buf, packet_len); | ||
217 | |||
218 | if (s->current_rx_buf) { | ||
219 | usbnet_skb_return(dev, buf); | ||
220 | s->current_rx_buf = NULL; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | return 1; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | error: | ||
229 | if (s->current_rx_buf) { | ||
230 | dev_kfree_skb_any(s->current_rx_buf); | ||
231 | s->current_rx_buf = NULL; | ||
232 | } | ||
233 | dev->net->stats.rx_errors++; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, | ||
238 | struct sk_buff *skb, gfp_t flags) | ||
239 | { | ||
240 | struct sk_buff *ret; | ||
241 | struct vl600_frame_hdr *frame; | ||
242 | struct vl600_pkt_hdr *packet; | ||
243 | static uint32_t serial = 1; | ||
244 | int orig_len = skb->len - sizeof(struct ethhdr); | ||
245 | int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3; | ||
246 | |||
247 | frame = (struct vl600_frame_hdr *) skb->data; | ||
248 | if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len)) | ||
249 | return skb; /* Already encapsulated? */ | ||
250 | |||
251 | if (skb->len < sizeof(struct ethhdr)) | ||
252 | /* Drop, device can only deal with ethernet packets */ | ||
253 | return NULL; | ||
254 | |||
255 | if (!skb_cloned(skb)) { | ||
256 | int headroom = skb_headroom(skb); | ||
257 | int tailroom = skb_tailroom(skb); | ||
258 | |||
259 | if (tailroom >= full_len - skb->len - sizeof(*frame) && | ||
260 | headroom >= sizeof(*frame)) | ||
261 | /* There's enough head and tail room */ | ||
262 | goto encapsulate; | ||
263 | |||
264 | if (headroom + tailroom + skb->len >= full_len) { | ||
265 | /* There's enough total room, just readjust */ | ||
266 | skb->data = memmove(skb->head + sizeof(*frame), | ||
267 | skb->data, skb->len); | ||
268 | skb_set_tail_pointer(skb, skb->len); | ||
269 | goto encapsulate; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /* Alloc a new skb with the required size */ | ||
274 | ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len - | ||
275 | skb->len - sizeof(struct vl600_frame_hdr), flags); | ||
276 | dev_kfree_skb_any(skb); | ||
277 | if (!ret) | ||
278 | return ret; | ||
279 | skb = ret; | ||
280 | |||
281 | encapsulate: | ||
282 | /* Packet header is same size as ethernet packet header | ||
283 | * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the | ||
284 | * h_proto field is in the same place so we just leave it alone and | ||
285 | * overwrite the remaining fields. | ||
286 | */ | ||
287 | packet = (struct vl600_pkt_hdr *) skb->data; | ||
288 | memset(&packet->dummy, 0, sizeof(packet->dummy)); | ||
289 | packet->len = cpu_to_le32(orig_len); | ||
290 | |||
291 | frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); | ||
292 | memset(frame, 0, sizeof(*frame)); | ||
293 | frame->len = cpu_to_le32(full_len); | ||
294 | frame->serial = cpu_to_le32(serial++); | ||
295 | frame->pkt_cnt = cpu_to_le32(1); | ||
296 | |||
297 | if (skb->len < full_len) /* Pad */ | ||
298 | skb_put(skb, full_len - skb->len); | ||
299 | |||
300 | return skb; | ||
301 | } | ||
302 | |||
303 | static const struct driver_info vl600_info = { | ||
304 | .description = "LG VL600 modem", | ||
305 | .flags = FLAG_ETHER | FLAG_RX_ASSEMBLE, | ||
306 | .bind = vl600_bind, | ||
307 | .unbind = vl600_unbind, | ||
308 | .status = usbnet_cdc_status, | ||
309 | .rx_fixup = vl600_rx_fixup, | ||
310 | .tx_fixup = vl600_tx_fixup, | ||
311 | }; | ||
312 | |||
313 | static const struct usb_device_id products[] = { | ||
314 | { | ||
315 | USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, | ||
316 | USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
317 | .driver_info = (unsigned long) &vl600_info, | ||
318 | }, | ||
319 | {}, /* End */ | ||
320 | }; | ||
321 | MODULE_DEVICE_TABLE(usb, products); | ||
322 | |||
323 | static struct usb_driver lg_vl600_driver = { | ||
324 | .name = "lg-vl600", | ||
325 | .id_table = products, | ||
326 | .probe = usbnet_probe, | ||
327 | .disconnect = usbnet_disconnect, | ||
328 | .suspend = usbnet_suspend, | ||
329 | .resume = usbnet_resume, | ||
330 | }; | ||
331 | |||
332 | static int __init vl600_init(void) | ||
333 | { | ||
334 | return usb_register(&lg_vl600_driver); | ||
335 | } | ||
336 | module_init(vl600_init); | ||
337 | |||
338 | static void __exit vl600_exit(void) | ||
339 | { | ||
340 | usb_deregister(&lg_vl600_driver); | ||
341 | } | ||
342 | module_exit(vl600_exit); | ||
343 | |||
344 | MODULE_AUTHOR("Anrzej Zaborowski"); | ||
345 | MODULE_DESCRIPTION("LG-VL600 modem's ethernet link"); | ||
346 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index a6281e3987b5..2b791392e788 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices | 2 | * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices |
3 | * | 3 | * |
4 | * based on usbnet.c, asix.c and the vendor provided mcs7830 driver | 4 | * based on usbnet.c, asix.c and the vendor provided mcs7830 driver |
5 | * | 5 | * |
@@ -11,6 +11,9 @@ | |||
11 | * | 11 | * |
12 | * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). | 12 | * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). |
13 | * | 13 | * |
14 | * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"), | ||
15 | * per active notification by manufacturer | ||
16 | * | ||
14 | * TODO: | 17 | * TODO: |
15 | * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) | 18 | * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) |
16 | * - implement ethtool_ops get_pauseparam/set_pauseparam | 19 | * - implement ethtool_ops get_pauseparam/set_pauseparam |
@@ -60,6 +63,7 @@ | |||
60 | #define MCS7830_MAX_MCAST 64 | 63 | #define MCS7830_MAX_MCAST 64 |
61 | 64 | ||
62 | #define MCS7830_VENDOR_ID 0x9710 | 65 | #define MCS7830_VENDOR_ID 0x9710 |
66 | #define MCS7832_PRODUCT_ID 0x7832 | ||
63 | #define MCS7830_PRODUCT_ID 0x7830 | 67 | #define MCS7830_PRODUCT_ID 0x7830 |
64 | #define MCS7730_PRODUCT_ID 0x7730 | 68 | #define MCS7730_PRODUCT_ID 0x7730 |
65 | 69 | ||
@@ -351,7 +355,7 @@ static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) | |||
351 | if (!ret) | 355 | if (!ret) |
352 | ret = mcs7830_write_phy(dev, MII_BMCR, | 356 | ret = mcs7830_write_phy(dev, MII_BMCR, |
353 | BMCR_ANENABLE | BMCR_ANRESTART ); | 357 | BMCR_ANENABLE | BMCR_ANRESTART ); |
354 | return ret < 0 ? : 0; | 358 | return ret; |
355 | } | 359 | } |
356 | 360 | ||
357 | 361 | ||
@@ -626,7 +630,7 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
626 | } | 630 | } |
627 | 631 | ||
628 | static const struct driver_info moschip_info = { | 632 | static const struct driver_info moschip_info = { |
629 | .description = "MOSCHIP 7830/7730 usb-NET adapter", | 633 | .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", |
630 | .bind = mcs7830_bind, | 634 | .bind = mcs7830_bind, |
631 | .rx_fixup = mcs7830_rx_fixup, | 635 | .rx_fixup = mcs7830_rx_fixup, |
632 | .flags = FLAG_ETHER, | 636 | .flags = FLAG_ETHER, |
@@ -645,6 +649,10 @@ static const struct driver_info sitecom_info = { | |||
645 | 649 | ||
646 | static const struct usb_device_id products[] = { | 650 | static const struct usb_device_id products[] = { |
647 | { | 651 | { |
652 | USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID), | ||
653 | .driver_info = (unsigned long) &moschip_info, | ||
654 | }, | ||
655 | { | ||
648 | USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), | 656 | USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), |
649 | .driver_info = (unsigned long) &moschip_info, | 657 | .driver_info = (unsigned long) &moschip_info, |
650 | }, | 658 | }, |
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index ba72a7281cb0..01db4602a39e 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c | |||
@@ -560,7 +560,7 @@ static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) | |||
560 | 560 | ||
561 | static const struct driver_info net1080_info = { | 561 | static const struct driver_info net1080_info = { |
562 | .description = "NetChip TurboCONNECT", | 562 | .description = "NetChip TurboCONNECT", |
563 | .flags = FLAG_FRAMING_NC, | 563 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC, |
564 | .bind = net1080_bind, | 564 | .bind = net1080_bind, |
565 | .reset = net1080_reset, | 565 | .reset = net1080_reset, |
566 | .check_connect = net1080_check_connect, | 566 | .check_connect = net1080_check_connect, |
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 6710f09346d6..ef3667690b12 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c | |||
@@ -359,7 +359,7 @@ fail: | |||
359 | 359 | ||
360 | static int mdio_read(struct net_device *dev, int phy_id, int loc) | 360 | static int mdio_read(struct net_device *dev, int phy_id, int loc) |
361 | { | 361 | { |
362 | pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); | 362 | pegasus_t *pegasus = netdev_priv(dev); |
363 | u16 res; | 363 | u16 res; |
364 | 364 | ||
365 | read_mii_word(pegasus, phy_id, loc, &res); | 365 | read_mii_word(pegasus, phy_id, loc, &res); |
@@ -397,7 +397,7 @@ fail: | |||
397 | 397 | ||
398 | static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) | 398 | static void mdio_write(struct net_device *dev, int phy_id, int loc, int val) |
399 | { | 399 | { |
400 | pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev); | 400 | pegasus_t *pegasus = netdev_priv(dev); |
401 | 401 | ||
402 | write_mii_word(pegasus, phy_id, loc, val); | 402 | write_mii_word(pegasus, phy_id, loc, val); |
403 | } | 403 | } |
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 08555f8b15f4..217aec8a768f 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com | 35 | * Prolific PL-2301/PL-2302 driver ... http://www.prolific.com.tw/ |
36 | * | 36 | * |
37 | * The protocol and handshaking used here should be bug-compatible | 37 | * The protocol and handshaking used here should be bug-compatible |
38 | * with the Linux 2.2 "plusb" driver, by Deti Fliegl. | 38 | * with the Linux 2.2 "plusb" driver, by Deti Fliegl. |
@@ -45,6 +45,14 @@ | |||
45 | * seems to get wedged under load. Prolific docs are weak, and | 45 | * seems to get wedged under load. Prolific docs are weak, and |
46 | * don't identify differences between PL2301 and PL2302, much less | 46 | * don't identify differences between PL2301 and PL2302, much less |
47 | * anything to explain the different PL2302 versions observed. | 47 | * anything to explain the different PL2302 versions observed. |
48 | * | ||
49 | * NOTE: pl2501 has several modes, including pl2301 and pl2302 | ||
50 | * compatibility. Some docs suggest the difference between 2301 | ||
51 | * and 2302 is only to make MS-Windows use a different driver... | ||
52 | * | ||
53 | * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on | ||
54 | * this chip are as usual incomplete about what control messages | ||
55 | * are supported. | ||
48 | */ | 56 | */ |
49 | 57 | ||
50 | /* | 58 | /* |
@@ -86,17 +94,21 @@ pl_set_QuickLink_features(struct usbnet *dev, int val) | |||
86 | 94 | ||
87 | static int pl_reset(struct usbnet *dev) | 95 | static int pl_reset(struct usbnet *dev) |
88 | { | 96 | { |
97 | int status; | ||
98 | |||
89 | /* some units seem to need this reset, others reject it utterly. | 99 | /* some units seem to need this reset, others reject it utterly. |
90 | * FIXME be more like "naplink" or windows drivers. | 100 | * FIXME be more like "naplink" or windows drivers. |
91 | */ | 101 | */ |
92 | (void) pl_set_QuickLink_features(dev, | 102 | status = pl_set_QuickLink_features(dev, |
93 | PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); | 103 | PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); |
104 | if (status != 0 && netif_msg_probe(dev)) | ||
105 | netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status); | ||
94 | return 0; | 106 | return 0; |
95 | } | 107 | } |
96 | 108 | ||
97 | static const struct driver_info prolific_info = { | 109 | static const struct driver_info prolific_info = { |
98 | .description = "Prolific PL-2301/PL-2302", | 110 | .description = "Prolific PL-2301/PL-2302/PL-25A1", |
99 | .flags = FLAG_NO_SETINT, | 111 | .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, |
100 | /* some PL-2302 versions seem to fail usb_set_interface() */ | 112 | /* some PL-2302 versions seem to fail usb_set_interface() */ |
101 | .reset = pl_reset, | 113 | .reset = pl_reset, |
102 | }; | 114 | }; |
@@ -111,6 +123,7 @@ static const struct driver_info prolific_info = { | |||
111 | 123 | ||
112 | static const struct usb_device_id products [] = { | 124 | static const struct usb_device_id products [] = { |
113 | 125 | ||
126 | /* full speed cables */ | ||
114 | { | 127 | { |
115 | USB_DEVICE(0x067b, 0x0000), // PL-2301 | 128 | USB_DEVICE(0x067b, 0x0000), // PL-2301 |
116 | .driver_info = (unsigned long) &prolific_info, | 129 | .driver_info = (unsigned long) &prolific_info, |
@@ -119,6 +132,15 @@ static const struct usb_device_id products [] = { | |||
119 | .driver_info = (unsigned long) &prolific_info, | 132 | .driver_info = (unsigned long) &prolific_info, |
120 | }, | 133 | }, |
121 | 134 | ||
135 | /* high speed cables */ | ||
136 | { | ||
137 | USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */ | ||
138 | .driver_info = (unsigned long) &prolific_info, | ||
139 | }, { | ||
140 | USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ | ||
141 | .driver_info = (unsigned long) &prolific_info, | ||
142 | }, | ||
143 | |||
122 | { }, // END | 144 | { }, // END |
123 | }; | 145 | }; |
124 | MODULE_DEVICE_TABLE(usb, products); | 146 | MODULE_DEVICE_TABLE(usb, products); |
@@ -134,16 +156,16 @@ static struct usb_driver plusb_driver = { | |||
134 | 156 | ||
135 | static int __init plusb_init(void) | 157 | static int __init plusb_init(void) |
136 | { | 158 | { |
137 | return usb_register(&plusb_driver); | 159 | return usb_register(&plusb_driver); |
138 | } | 160 | } |
139 | module_init(plusb_init); | 161 | module_init(plusb_init); |
140 | 162 | ||
141 | static void __exit plusb_exit(void) | 163 | static void __exit plusb_exit(void) |
142 | { | 164 | { |
143 | usb_deregister(&plusb_driver); | 165 | usb_deregister(&plusb_driver); |
144 | } | 166 | } |
145 | module_exit(plusb_exit); | 167 | module_exit(plusb_exit); |
146 | 168 | ||
147 | MODULE_AUTHOR("David Brownell"); | 169 | MODULE_AUTHOR("David Brownell"); |
148 | MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver"); | 170 | MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver"); |
149 | MODULE_LICENSE("GPL"); | 171 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index dd8a4adf48ca..255d6a424a6b 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c | |||
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, | |||
104 | int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) | 104 | int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) |
105 | { | 105 | { |
106 | struct cdc_state *info = (void *) &dev->data; | 106 | struct cdc_state *info = (void *) &dev->data; |
107 | struct usb_cdc_notification notification; | ||
107 | int master_ifnum; | 108 | int master_ifnum; |
108 | int retval; | 109 | int retval; |
110 | int partial; | ||
109 | unsigned count; | 111 | unsigned count; |
110 | __le32 rsp; | 112 | __le32 rsp; |
111 | u32 xid = 0, msg_len, request_id; | 113 | u32 xid = 0, msg_len, request_id; |
@@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) | |||
133 | if (unlikely(retval < 0 || xid == 0)) | 135 | if (unlikely(retval < 0 || xid == 0)) |
134 | return retval; | 136 | return retval; |
135 | 137 | ||
136 | // FIXME Seems like some devices discard responses when | 138 | /* Some devices don't respond on the control channel until |
137 | // we time out and cancel our "get response" requests... | 139 | * polled on the status channel, so do that first. */ |
138 | // so, this is fragile. Probably need to poll for status. | 140 | if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) { |
141 | retval = usb_interrupt_msg( | ||
142 | dev->udev, | ||
143 | usb_rcvintpipe(dev->udev, | ||
144 | dev->status->desc.bEndpointAddress), | ||
145 | ¬ification, sizeof(notification), &partial, | ||
146 | RNDIS_CONTROL_TIMEOUT_MS); | ||
147 | if (unlikely(retval < 0)) | ||
148 | return retval; | ||
149 | } | ||
139 | 150 | ||
140 | /* ignore status endpoint, just poll the control channel; | 151 | /* Poll the control channel; the request probably completed immediately */ |
141 | * the request probably completed immediately | ||
142 | */ | ||
143 | rsp = buf->msg_type | RNDIS_MSG_COMPLETION; | 152 | rsp = buf->msg_type | RNDIS_MSG_COMPLETION; |
144 | for (count = 0; count < 10; count++) { | 153 | for (count = 0; count < 10; count++) { |
145 | memset(buf, 0, CONTROL_BUFFER_SIZE); | 154 | memset(buf, 0, CONTROL_BUFFER_SIZE); |
@@ -573,7 +582,18 @@ EXPORT_SYMBOL_GPL(rndis_tx_fixup); | |||
573 | 582 | ||
574 | static const struct driver_info rndis_info = { | 583 | static const struct driver_info rndis_info = { |
575 | .description = "RNDIS device", | 584 | .description = "RNDIS device", |
576 | .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 585 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, |
586 | .bind = rndis_bind, | ||
587 | .unbind = rndis_unbind, | ||
588 | .status = rndis_status, | ||
589 | .rx_fixup = rndis_rx_fixup, | ||
590 | .tx_fixup = rndis_tx_fixup, | ||
591 | }; | ||
592 | |||
593 | static const struct driver_info rndis_poll_status_info = { | ||
594 | .description = "RNDIS device (poll status before control)", | ||
595 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, | ||
596 | .data = RNDIS_DRIVER_DATA_POLL_STATUS, | ||
577 | .bind = rndis_bind, | 597 | .bind = rndis_bind, |
578 | .unbind = rndis_unbind, | 598 | .unbind = rndis_unbind, |
579 | .status = rndis_status, | 599 | .status = rndis_status, |
@@ -585,13 +605,18 @@ static const struct driver_info rndis_info = { | |||
585 | 605 | ||
586 | static const struct usb_device_id products [] = { | 606 | static const struct usb_device_id products [] = { |
587 | { | 607 | { |
608 | /* 2Wire HomePortal 1000SW */ | ||
609 | USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042, | ||
610 | USB_CLASS_COMM, 2 /* ACM */, 0x0ff), | ||
611 | .driver_info = (unsigned long) &rndis_poll_status_info, | ||
612 | }, { | ||
588 | /* RNDIS is MSFT's un-official variant of CDC ACM */ | 613 | /* RNDIS is MSFT's un-official variant of CDC ACM */ |
589 | USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), | 614 | USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), |
590 | .driver_info = (unsigned long) &rndis_info, | 615 | .driver_info = (unsigned long) &rndis_info, |
591 | }, { | 616 | }, { |
592 | /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ | 617 | /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ |
593 | USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), | 618 | USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), |
594 | .driver_info = (unsigned long) &rndis_info, | 619 | .driver_info = (unsigned long) &rndis_poll_status_info, |
595 | }, { | 620 | }, { |
596 | /* RNDIS for tethering */ | 621 | /* RNDIS for tethering */ |
597 | USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), | 622 | USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), |
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index e85c89c6706d..041fb7d43c4f 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c | |||
@@ -843,10 +843,11 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e | |||
843 | get_registers(dev, BMCR, 2, &bmcr); | 843 | get_registers(dev, BMCR, 2, &bmcr); |
844 | get_registers(dev, ANLP, 2, &lpa); | 844 | get_registers(dev, ANLP, 2, &lpa); |
845 | if (bmcr & BMCR_ANENABLE) { | 845 | if (bmcr & BMCR_ANENABLE) { |
846 | u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ? | ||
847 | SPEED_100 : SPEED_10); | ||
848 | ethtool_cmd_speed_set(ecmd, speed); | ||
846 | ecmd->autoneg = AUTONEG_ENABLE; | 849 | ecmd->autoneg = AUTONEG_ENABLE; |
847 | ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ? | 850 | if (speed == SPEED_100) |
848 | SPEED_100 : SPEED_10; | ||
849 | if (ecmd->speed == SPEED_100) | ||
850 | ecmd->duplex = (lpa & LPA_100FULL) ? | 851 | ecmd->duplex = (lpa & LPA_100FULL) ? |
851 | DUPLEX_FULL : DUPLEX_HALF; | 852 | DUPLEX_FULL : DUPLEX_HALF; |
852 | else | 853 | else |
@@ -854,8 +855,8 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e | |||
854 | DUPLEX_FULL : DUPLEX_HALF; | 855 | DUPLEX_FULL : DUPLEX_HALF; |
855 | } else { | 856 | } else { |
856 | ecmd->autoneg = AUTONEG_DISABLE; | 857 | ecmd->autoneg = AUTONEG_DISABLE; |
857 | ecmd->speed = (bmcr & BMCR_SPEED100) ? | 858 | ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ? |
858 | SPEED_100 : SPEED_10; | 859 | SPEED_100 : SPEED_10)); |
859 | ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? | 860 | ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? |
860 | DUPLEX_FULL : DUPLEX_HALF; | 861 | DUPLEX_FULL : DUPLEX_HALF; |
861 | } | 862 | } |
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index ee85c8b9a858..ed1b43210584 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c | |||
@@ -203,7 +203,7 @@ static inline void sierra_net_set_private(struct usbnet *dev, | |||
203 | /* is packet IPv4 */ | 203 | /* is packet IPv4 */ |
204 | static inline int is_ip(struct sk_buff *skb) | 204 | static inline int is_ip(struct sk_buff *skb) |
205 | { | 205 | { |
206 | return (skb->protocol == cpu_to_be16(ETH_P_IP)); | 206 | return skb->protocol == cpu_to_be16(ETH_P_IP); |
207 | } | 207 | } |
208 | 208 | ||
209 | /* | 209 | /* |
@@ -354,7 +354,7 @@ static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix) | |||
354 | 354 | ||
355 | static inline int sierra_net_is_valid_addrlen(u8 len) | 355 | static inline int sierra_net_is_valid_addrlen(u8 len) |
356 | { | 356 | { |
357 | return (len == sizeof(struct in_addr)); | 357 | return len == sizeof(struct in_addr); |
358 | } | 358 | } |
359 | 359 | ||
360 | static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) | 360 | static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) |
@@ -802,10 +802,9 @@ static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf) | |||
802 | 802 | ||
803 | dev_dbg(&dev->udev->dev, "%s", __func__); | 803 | dev_dbg(&dev->udev->dev, "%s", __func__); |
804 | 804 | ||
805 | /* Kill the timer then flush the work queue */ | 805 | /* kill the timer and work */ |
806 | del_timer_sync(&priv->sync_timer); | 806 | del_timer_sync(&priv->sync_timer); |
807 | 807 | cancel_work_sync(&priv->sierra_net_kevent); | |
808 | flush_scheduled_work(); | ||
809 | 808 | ||
810 | /* tell modem we are going away */ | 809 | /* tell modem we are going away */ |
811 | status = sierra_net_send_cmd(dev, priv->shdwn_msg, | 810 | status = sierra_net_send_cmd(dev, priv->shdwn_msg, |
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6eb7edd..15b3d6888ae9 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c | |||
@@ -65,7 +65,6 @@ struct smsc75xx_priv { | |||
65 | struct usbnet *dev; | 65 | struct usbnet *dev; |
66 | u32 rfe_ctl; | 66 | u32 rfe_ctl; |
67 | u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; | 67 | u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; |
68 | bool use_rx_csum; | ||
69 | struct mutex dataport_mutex; | 68 | struct mutex dataport_mutex; |
70 | spinlock_t rfe_ctl_lock; | 69 | spinlock_t rfe_ctl_lock; |
71 | struct work_struct set_multicast; | 70 | struct work_struct set_multicast; |
@@ -504,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, | |||
504 | static int smsc75xx_link_reset(struct usbnet *dev) | 503 | static int smsc75xx_link_reset(struct usbnet *dev) |
505 | { | 504 | { |
506 | struct mii_if_info *mii = &dev->mii; | 505 | struct mii_if_info *mii = &dev->mii; |
507 | struct ethtool_cmd ecmd; | 506 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
508 | u16 lcladv, rmtadv; | 507 | u16 lcladv, rmtadv; |
509 | int ret; | 508 | int ret; |
510 | 509 | ||
@@ -520,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) | |||
520 | lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); | 519 | lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); |
521 | rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); | 520 | rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); |
522 | 521 | ||
523 | netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" | 522 | netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" |
524 | " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); | 523 | " rmtadv: %04x", ethtool_cmd_speed(&ecmd), |
524 | ecmd.duplex, lcladv, rmtadv); | ||
525 | 525 | ||
526 | return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); | 526 | return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); |
527 | } | 527 | } |
@@ -548,28 +548,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb) | |||
548 | "unexpected interrupt, intdata=0x%08X", intdata); | 548 | "unexpected interrupt, intdata=0x%08X", intdata); |
549 | } | 549 | } |
550 | 550 | ||
551 | /* Enable or disable Rx checksum offload engine */ | ||
552 | static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) | ||
553 | { | ||
554 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
555 | unsigned long flags; | ||
556 | int ret; | ||
557 | |||
558 | spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | ||
559 | |||
560 | if (pdata->use_rx_csum) | ||
561 | pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; | ||
562 | else | ||
563 | pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); | ||
564 | |||
565 | spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | ||
566 | |||
567 | ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | ||
568 | check_warn_return(ret, "Error writing RFE_CTL"); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) | 551 | static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) |
574 | { | 552 | { |
575 | return MAX_EEPROM_SIZE; | 553 | return MAX_EEPROM_SIZE; |
@@ -599,34 +577,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, | |||
599 | return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); | 577 | return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); |
600 | } | 578 | } |
601 | 579 | ||
602 | static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) | ||
603 | { | ||
604 | struct usbnet *dev = netdev_priv(netdev); | ||
605 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
606 | |||
607 | return pdata->use_rx_csum; | ||
608 | } | ||
609 | |||
610 | static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) | ||
611 | { | ||
612 | struct usbnet *dev = netdev_priv(netdev); | ||
613 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
614 | |||
615 | pdata->use_rx_csum = !!val; | ||
616 | |||
617 | return smsc75xx_set_rx_csum_offload(dev); | ||
618 | } | ||
619 | |||
620 | static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) | ||
621 | { | ||
622 | if (data) | ||
623 | netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; | ||
624 | else | ||
625 | netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static const struct ethtool_ops smsc75xx_ethtool_ops = { | 580 | static const struct ethtool_ops smsc75xx_ethtool_ops = { |
631 | .get_link = usbnet_get_link, | 581 | .get_link = usbnet_get_link, |
632 | .nway_reset = usbnet_nway_reset, | 582 | .nway_reset = usbnet_nway_reset, |
@@ -638,12 +588,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = { | |||
638 | .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, | 588 | .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, |
639 | .get_eeprom = smsc75xx_ethtool_get_eeprom, | 589 | .get_eeprom = smsc75xx_ethtool_get_eeprom, |
640 | .set_eeprom = smsc75xx_ethtool_set_eeprom, | 590 | .set_eeprom = smsc75xx_ethtool_set_eeprom, |
641 | .get_tx_csum = ethtool_op_get_tx_csum, | ||
642 | .set_tx_csum = ethtool_op_set_tx_hw_csum, | ||
643 | .get_rx_csum = smsc75xx_ethtool_get_rx_csum, | ||
644 | .set_rx_csum = smsc75xx_ethtool_set_rx_csum, | ||
645 | .get_tso = ethtool_op_get_tso, | ||
646 | .set_tso = smsc75xx_ethtool_set_tso, | ||
647 | }; | 591 | }; |
648 | 592 | ||
649 | static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 593 | static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -782,6 +726,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) | |||
782 | return usbnet_change_mtu(netdev, new_mtu); | 726 | return usbnet_change_mtu(netdev, new_mtu); |
783 | } | 727 | } |
784 | 728 | ||
729 | /* Enable or disable Rx checksum offload engine */ | ||
730 | static int smsc75xx_set_features(struct net_device *netdev, u32 features) | ||
731 | { | ||
732 | struct usbnet *dev = netdev_priv(netdev); | ||
733 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
734 | unsigned long flags; | ||
735 | int ret; | ||
736 | |||
737 | spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); | ||
738 | |||
739 | if (features & NETIF_F_RXCSUM) | ||
740 | pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; | ||
741 | else | ||
742 | pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); | ||
743 | |||
744 | spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); | ||
745 | /* it's racing here! */ | ||
746 | |||
747 | ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | ||
748 | check_warn_return(ret, "Error writing RFE_CTL"); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
785 | static int smsc75xx_reset(struct usbnet *dev) | 753 | static int smsc75xx_reset(struct usbnet *dev) |
786 | { | 754 | { |
787 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | 755 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); |
@@ -960,11 +928,7 @@ static int smsc75xx_reset(struct usbnet *dev) | |||
960 | netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); | 928 | netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); |
961 | 929 | ||
962 | /* Enable or disable checksum offload engines */ | 930 | /* Enable or disable checksum offload engines */ |
963 | ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); | 931 | smsc75xx_set_features(dev->net, dev->net->features); |
964 | ret = smsc75xx_set_rx_csum_offload(dev); | ||
965 | check_warn_return(ret, "Failed to set rx csum offload: %d", ret); | ||
966 | |||
967 | smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); | ||
968 | 932 | ||
969 | smsc75xx_set_multicast(dev->net); | 933 | smsc75xx_set_multicast(dev->net); |
970 | 934 | ||
@@ -1037,6 +1001,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = { | |||
1037 | .ndo_validate_addr = eth_validate_addr, | 1001 | .ndo_validate_addr = eth_validate_addr, |
1038 | .ndo_do_ioctl = smsc75xx_ioctl, | 1002 | .ndo_do_ioctl = smsc75xx_ioctl, |
1039 | .ndo_set_multicast_list = smsc75xx_set_multicast, | 1003 | .ndo_set_multicast_list = smsc75xx_set_multicast, |
1004 | .ndo_set_features = smsc75xx_set_features, | ||
1040 | }; | 1005 | }; |
1041 | 1006 | ||
1042 | static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) | 1007 | static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) |
@@ -1065,10 +1030,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1065 | 1030 | ||
1066 | INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); | 1031 | INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); |
1067 | 1032 | ||
1068 | pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; | 1033 | if (DEFAULT_TX_CSUM_ENABLE) { |
1034 | dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; | ||
1035 | if (DEFAULT_TSO_ENABLE) | ||
1036 | dev->net->features |= NETIF_F_SG | | ||
1037 | NETIF_F_TSO | NETIF_F_TSO6; | ||
1038 | } | ||
1039 | if (DEFAULT_RX_CSUM_ENABLE) | ||
1040 | dev->net->features |= NETIF_F_RXCSUM; | ||
1069 | 1041 | ||
1070 | /* We have to advertise SG otherwise TSO cannot be enabled */ | 1042 | dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
1071 | dev->net->features |= NETIF_F_SG; | 1043 | NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; |
1072 | 1044 | ||
1073 | /* Init all registers */ | 1045 | /* Init all registers */ |
1074 | ret = smsc75xx_reset(dev); | 1046 | ret = smsc75xx_reset(dev); |
@@ -1091,10 +1063,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) | |||
1091 | } | 1063 | } |
1092 | } | 1064 | } |
1093 | 1065 | ||
1094 | static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, | 1066 | static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, |
1095 | u32 rx_cmd_b) | 1067 | u32 rx_cmd_a, u32 rx_cmd_b) |
1096 | { | 1068 | { |
1097 | if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { | 1069 | if (!(dev->net->features & NETIF_F_RXCSUM) || |
1070 | unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { | ||
1098 | skb->ip_summed = CHECKSUM_NONE; | 1071 | skb->ip_summed = CHECKSUM_NONE; |
1099 | } else { | 1072 | } else { |
1100 | skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); | 1073 | skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); |
@@ -1104,8 +1077,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, | |||
1104 | 1077 | ||
1105 | static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 1078 | static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
1106 | { | 1079 | { |
1107 | struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); | ||
1108 | |||
1109 | while (skb->len > 0) { | 1080 | while (skb->len > 0) { |
1110 | u32 rx_cmd_a, rx_cmd_b, align_count, size; | 1081 | u32 rx_cmd_a, rx_cmd_b, align_count, size; |
1111 | struct sk_buff *ax_skb; | 1082 | struct sk_buff *ax_skb; |
@@ -1145,11 +1116,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1145 | 1116 | ||
1146 | /* last frame in this batch */ | 1117 | /* last frame in this batch */ |
1147 | if (skb->len == size) { | 1118 | if (skb->len == size) { |
1148 | if (pdata->use_rx_csum) | 1119 | smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, |
1149 | smsc75xx_rx_csum_offload(skb, rx_cmd_a, | 1120 | rx_cmd_b); |
1150 | rx_cmd_b); | ||
1151 | else | ||
1152 | skb->ip_summed = CHECKSUM_NONE; | ||
1153 | 1121 | ||
1154 | skb_trim(skb, skb->len - 4); /* remove fcs */ | 1122 | skb_trim(skb, skb->len - 4); /* remove fcs */ |
1155 | skb->truesize = size + sizeof(struct sk_buff); | 1123 | skb->truesize = size + sizeof(struct sk_buff); |
@@ -1167,11 +1135,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1167 | ax_skb->data = packet; | 1135 | ax_skb->data = packet; |
1168 | skb_set_tail_pointer(ax_skb, size); | 1136 | skb_set_tail_pointer(ax_skb, size); |
1169 | 1137 | ||
1170 | if (pdata->use_rx_csum) | 1138 | smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, |
1171 | smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, | 1139 | rx_cmd_b); |
1172 | rx_cmd_b); | ||
1173 | else | ||
1174 | ax_skb->ip_summed = CHECKSUM_NONE; | ||
1175 | 1140 | ||
1176 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | 1141 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ |
1177 | ax_skb->truesize = size + sizeof(struct sk_buff); | 1142 | ax_skb->truesize = size + sizeof(struct sk_buff); |
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 12a3c88c5282..f74f3ce71526 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -49,9 +49,9 @@ | |||
49 | 49 | ||
50 | struct smsc95xx_priv { | 50 | struct smsc95xx_priv { |
51 | u32 mac_cr; | 51 | u32 mac_cr; |
52 | u32 hash_hi; | ||
53 | u32 hash_lo; | ||
52 | spinlock_t mac_cr_lock; | 54 | spinlock_t mac_cr_lock; |
53 | bool use_tx_csum; | ||
54 | bool use_rx_csum; | ||
55 | }; | 55 | }; |
56 | 56 | ||
57 | struct usb_context { | 57 | struct usb_context { |
@@ -370,10 +370,11 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
370 | { | 370 | { |
371 | struct usbnet *dev = netdev_priv(netdev); | 371 | struct usbnet *dev = netdev_priv(netdev); |
372 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 372 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
373 | u32 hash_hi = 0; | ||
374 | u32 hash_lo = 0; | ||
375 | unsigned long flags; | 373 | unsigned long flags; |
376 | 374 | ||
375 | pdata->hash_hi = 0; | ||
376 | pdata->hash_lo = 0; | ||
377 | |||
377 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); | 378 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); |
378 | 379 | ||
379 | if (dev->net->flags & IFF_PROMISC) { | 380 | if (dev->net->flags & IFF_PROMISC) { |
@@ -394,13 +395,13 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
394 | u32 bitnum = smsc95xx_hash(ha->addr); | 395 | u32 bitnum = smsc95xx_hash(ha->addr); |
395 | u32 mask = 0x01 << (bitnum & 0x1F); | 396 | u32 mask = 0x01 << (bitnum & 0x1F); |
396 | if (bitnum & 0x20) | 397 | if (bitnum & 0x20) |
397 | hash_hi |= mask; | 398 | pdata->hash_hi |= mask; |
398 | else | 399 | else |
399 | hash_lo |= mask; | 400 | pdata->hash_lo |= mask; |
400 | } | 401 | } |
401 | 402 | ||
402 | netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", | 403 | netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", |
403 | hash_hi, hash_lo); | 404 | pdata->hash_hi, pdata->hash_lo); |
404 | } else { | 405 | } else { |
405 | netif_dbg(dev, drv, dev->net, "receive own packets only\n"); | 406 | netif_dbg(dev, drv, dev->net, "receive own packets only\n"); |
406 | pdata->mac_cr &= | 407 | pdata->mac_cr &= |
@@ -410,8 +411,8 @@ static void smsc95xx_set_multicast(struct net_device *netdev) | |||
410 | spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); | 411 | spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); |
411 | 412 | ||
412 | /* Initiate async writes, as we can't wait for completion here */ | 413 | /* Initiate async writes, as we can't wait for completion here */ |
413 | smsc95xx_write_reg_async(dev, HASHH, &hash_hi); | 414 | smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi); |
414 | smsc95xx_write_reg_async(dev, HASHL, &hash_lo); | 415 | smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo); |
415 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); | 416 | smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); |
416 | } | 417 | } |
417 | 418 | ||
@@ -456,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev) | |||
456 | { | 457 | { |
457 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 458 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
458 | struct mii_if_info *mii = &dev->mii; | 459 | struct mii_if_info *mii = &dev->mii; |
459 | struct ethtool_cmd ecmd; | 460 | struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; |
460 | unsigned long flags; | 461 | unsigned long flags; |
461 | u16 lcladv, rmtadv; | 462 | u16 lcladv, rmtadv; |
462 | u32 intdata; | 463 | u32 intdata; |
@@ -471,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev) | |||
471 | lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); | 472 | lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); |
472 | rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); | 473 | rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA); |
473 | 474 | ||
474 | netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n", | 475 | netif_dbg(dev, link, dev->net, |
475 | ecmd.speed, ecmd.duplex, lcladv, rmtadv); | 476 | "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n", |
477 | ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv); | ||
476 | 478 | ||
477 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); | 479 | spin_lock_irqsave(&pdata->mac_cr_lock, flags); |
478 | if (ecmd.duplex != DUPLEX_FULL) { | 480 | if (ecmd.duplex != DUPLEX_FULL) { |
@@ -514,22 +516,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) | |||
514 | } | 516 | } |
515 | 517 | ||
516 | /* Enable or disable Tx & Rx checksum offload engines */ | 518 | /* Enable or disable Tx & Rx checksum offload engines */ |
517 | static int smsc95xx_set_csums(struct usbnet *dev) | 519 | static int smsc95xx_set_features(struct net_device *netdev, u32 features) |
518 | { | 520 | { |
519 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 521 | struct usbnet *dev = netdev_priv(netdev); |
520 | u32 read_buf; | 522 | u32 read_buf; |
521 | int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | 523 | int ret; |
524 | |||
525 | ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); | ||
522 | if (ret < 0) { | 526 | if (ret < 0) { |
523 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); | 527 | netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret); |
524 | return ret; | 528 | return ret; |
525 | } | 529 | } |
526 | 530 | ||
527 | if (pdata->use_tx_csum) | 531 | if (features & NETIF_F_HW_CSUM) |
528 | read_buf |= Tx_COE_EN_; | 532 | read_buf |= Tx_COE_EN_; |
529 | else | 533 | else |
530 | read_buf &= ~Tx_COE_EN_; | 534 | read_buf &= ~Tx_COE_EN_; |
531 | 535 | ||
532 | if (pdata->use_rx_csum) | 536 | if (features & NETIF_F_RXCSUM) |
533 | read_buf |= Rx_COE_EN_; | 537 | read_buf |= Rx_COE_EN_; |
534 | else | 538 | else |
535 | read_buf &= ~Rx_COE_EN_; | 539 | read_buf &= ~Rx_COE_EN_; |
@@ -573,43 +577,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev, | |||
573 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); | 577 | return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data); |
574 | } | 578 | } |
575 | 579 | ||
576 | static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev) | ||
577 | { | ||
578 | struct usbnet *dev = netdev_priv(netdev); | ||
579 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
580 | |||
581 | return pdata->use_rx_csum; | ||
582 | } | ||
583 | |||
584 | static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) | ||
585 | { | ||
586 | struct usbnet *dev = netdev_priv(netdev); | ||
587 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
588 | |||
589 | pdata->use_rx_csum = !!val; | ||
590 | |||
591 | return smsc95xx_set_csums(dev); | ||
592 | } | ||
593 | |||
594 | static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) | ||
595 | { | ||
596 | struct usbnet *dev = netdev_priv(netdev); | ||
597 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
598 | |||
599 | return pdata->use_tx_csum; | ||
600 | } | ||
601 | |||
602 | static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) | ||
603 | { | ||
604 | struct usbnet *dev = netdev_priv(netdev); | ||
605 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
606 | |||
607 | pdata->use_tx_csum = !!val; | ||
608 | |||
609 | ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); | ||
610 | return smsc95xx_set_csums(dev); | ||
611 | } | ||
612 | |||
613 | static const struct ethtool_ops smsc95xx_ethtool_ops = { | 580 | static const struct ethtool_ops smsc95xx_ethtool_ops = { |
614 | .get_link = usbnet_get_link, | 581 | .get_link = usbnet_get_link, |
615 | .nway_reset = usbnet_nway_reset, | 582 | .nway_reset = usbnet_nway_reset, |
@@ -621,10 +588,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = { | |||
621 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, | 588 | .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, |
622 | .get_eeprom = smsc95xx_ethtool_get_eeprom, | 589 | .get_eeprom = smsc95xx_ethtool_get_eeprom, |
623 | .set_eeprom = smsc95xx_ethtool_set_eeprom, | 590 | .set_eeprom = smsc95xx_ethtool_set_eeprom, |
624 | .get_tx_csum = smsc95xx_ethtool_get_tx_csum, | ||
625 | .set_tx_csum = smsc95xx_ethtool_set_tx_csum, | ||
626 | .get_rx_csum = smsc95xx_ethtool_get_rx_csum, | ||
627 | .set_rx_csum = smsc95xx_ethtool_set_rx_csum, | ||
628 | }; | 591 | }; |
629 | 592 | ||
630 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | 593 | static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) |
@@ -727,7 +690,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) | |||
727 | msleep(10); | 690 | msleep(10); |
728 | bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); | 691 | bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); |
729 | timeout++; | 692 | timeout++; |
730 | } while ((bmcr & MII_BMCR) && (timeout < 100)); | 693 | } while ((bmcr & BMCR_RESET) && (timeout < 100)); |
731 | 694 | ||
732 | if (timeout >= 100) { | 695 | if (timeout >= 100) { |
733 | netdev_warn(dev->net, "timeout on PHY Reset"); | 696 | netdev_warn(dev->net, "timeout on PHY Reset"); |
@@ -752,7 +715,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) | |||
752 | static int smsc95xx_reset(struct usbnet *dev) | 715 | static int smsc95xx_reset(struct usbnet *dev) |
753 | { | 716 | { |
754 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 717 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); |
755 | struct net_device *netdev = dev->net; | ||
756 | u32 read_buf, write_buf, burst_cap; | 718 | u32 read_buf, write_buf, burst_cap; |
757 | int ret = 0, timeout; | 719 | int ret = 0, timeout; |
758 | 720 | ||
@@ -805,8 +767,6 @@ static int smsc95xx_reset(struct usbnet *dev) | |||
805 | return ret; | 767 | return ret; |
806 | } | 768 | } |
807 | 769 | ||
808 | smsc95xx_init_mac_address(dev); | ||
809 | |||
810 | ret = smsc95xx_set_mac_address(dev); | 770 | ret = smsc95xx_set_mac_address(dev); |
811 | if (ret < 0) | 771 | if (ret < 0) |
812 | return ret; | 772 | return ret; |
@@ -974,12 +934,7 @@ static int smsc95xx_reset(struct usbnet *dev) | |||
974 | } | 934 | } |
975 | 935 | ||
976 | /* Enable or disable checksum offload engines */ | 936 | /* Enable or disable checksum offload engines */ |
977 | ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); | 937 | smsc95xx_set_features(dev->net, dev->net->features); |
978 | ret = smsc95xx_set_csums(dev); | ||
979 | if (ret < 0) { | ||
980 | netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret); | ||
981 | return ret; | ||
982 | } | ||
983 | 938 | ||
984 | smsc95xx_set_multicast(dev->net); | 939 | smsc95xx_set_multicast(dev->net); |
985 | 940 | ||
@@ -1018,6 +973,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = { | |||
1018 | .ndo_validate_addr = eth_validate_addr, | 973 | .ndo_validate_addr = eth_validate_addr, |
1019 | .ndo_do_ioctl = smsc95xx_ioctl, | 974 | .ndo_do_ioctl = smsc95xx_ioctl, |
1020 | .ndo_set_multicast_list = smsc95xx_set_multicast, | 975 | .ndo_set_multicast_list = smsc95xx_set_multicast, |
976 | .ndo_set_features = smsc95xx_set_features, | ||
1021 | }; | 977 | }; |
1022 | 978 | ||
1023 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | 979 | static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) |
@@ -1044,8 +1000,14 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1044 | 1000 | ||
1045 | spin_lock_init(&pdata->mac_cr_lock); | 1001 | spin_lock_init(&pdata->mac_cr_lock); |
1046 | 1002 | ||
1047 | pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; | 1003 | if (DEFAULT_TX_CSUM_ENABLE) |
1048 | pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; | 1004 | dev->net->features |= NETIF_F_HW_CSUM; |
1005 | if (DEFAULT_RX_CSUM_ENABLE) | ||
1006 | dev->net->features |= NETIF_F_RXCSUM; | ||
1007 | |||
1008 | dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM; | ||
1009 | |||
1010 | smsc95xx_init_mac_address(dev); | ||
1049 | 1011 | ||
1050 | /* Init all registers */ | 1012 | /* Init all registers */ |
1051 | ret = smsc95xx_reset(dev); | 1013 | ret = smsc95xx_reset(dev); |
@@ -1053,7 +1015,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) | |||
1053 | dev->net->netdev_ops = &smsc95xx_netdev_ops; | 1015 | dev->net->netdev_ops = &smsc95xx_netdev_ops; |
1054 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; | 1016 | dev->net->ethtool_ops = &smsc95xx_ethtool_ops; |
1055 | dev->net->flags |= IFF_MULTICAST; | 1017 | dev->net->flags |= IFF_MULTICAST; |
1056 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD; | 1018 | dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; |
1057 | return 0; | 1019 | return 0; |
1058 | } | 1020 | } |
1059 | 1021 | ||
@@ -1077,8 +1039,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) | |||
1077 | 1039 | ||
1078 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 1040 | static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
1079 | { | 1041 | { |
1080 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | ||
1081 | |||
1082 | while (skb->len > 0) { | 1042 | while (skb->len > 0) { |
1083 | u32 header, align_count; | 1043 | u32 header, align_count; |
1084 | struct sk_buff *ax_skb; | 1044 | struct sk_buff *ax_skb; |
@@ -1120,7 +1080,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1120 | 1080 | ||
1121 | /* last frame in this batch */ | 1081 | /* last frame in this batch */ |
1122 | if (skb->len == size) { | 1082 | if (skb->len == size) { |
1123 | if (pdata->use_rx_csum) | 1083 | if (dev->net->features & NETIF_F_RXCSUM) |
1124 | smsc95xx_rx_csum_offload(skb); | 1084 | smsc95xx_rx_csum_offload(skb); |
1125 | skb_trim(skb, skb->len - 4); /* remove fcs */ | 1085 | skb_trim(skb, skb->len - 4); /* remove fcs */ |
1126 | skb->truesize = size + sizeof(struct sk_buff); | 1086 | skb->truesize = size + sizeof(struct sk_buff); |
@@ -1138,7 +1098,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1138 | ax_skb->data = packet; | 1098 | ax_skb->data = packet; |
1139 | skb_set_tail_pointer(ax_skb, size); | 1099 | skb_set_tail_pointer(ax_skb, size); |
1140 | 1100 | ||
1141 | if (pdata->use_rx_csum) | 1101 | if (dev->net->features & NETIF_F_RXCSUM) |
1142 | smsc95xx_rx_csum_offload(ax_skb); | 1102 | smsc95xx_rx_csum_offload(ax_skb); |
1143 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ | 1103 | skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ |
1144 | ax_skb->truesize = size + sizeof(struct sk_buff); | 1104 | ax_skb->truesize = size + sizeof(struct sk_buff); |
@@ -1163,17 +1123,15 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
1163 | 1123 | ||
1164 | static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) | 1124 | static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) |
1165 | { | 1125 | { |
1166 | int len = skb->data - skb->head; | 1126 | u16 low_16 = (u16)skb_checksum_start_offset(skb); |
1167 | u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len); | 1127 | u16 high_16 = low_16 + skb->csum_offset; |
1168 | u16 low_16 = (u16)(skb->csum_start - len); | ||
1169 | return (high_16 << 16) | low_16; | 1128 | return (high_16 << 16) | low_16; |
1170 | } | 1129 | } |
1171 | 1130 | ||
1172 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | 1131 | static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, |
1173 | struct sk_buff *skb, gfp_t flags) | 1132 | struct sk_buff *skb, gfp_t flags) |
1174 | { | 1133 | { |
1175 | struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | 1134 | bool csum = skb->ip_summed == CHECKSUM_PARTIAL; |
1176 | bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); | ||
1177 | int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; | 1135 | int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; |
1178 | u32 tx_cmd_a, tx_cmd_b; | 1136 | u32 tx_cmd_a, tx_cmd_b; |
1179 | 1137 | ||
@@ -1193,7 +1151,7 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | |||
1193 | if (skb->len <= 45) { | 1151 | if (skb->len <= 45) { |
1194 | /* workaround - hardware tx checksum does not work | 1152 | /* workaround - hardware tx checksum does not work |
1195 | * properly with extremely small packets */ | 1153 | * properly with extremely small packets */ |
1196 | long csstart = skb->csum_start - skb_headroom(skb); | 1154 | long csstart = skb_checksum_start_offset(skb); |
1197 | __wsum calc = csum_partial(skb->data + csstart, | 1155 | __wsum calc = csum_partial(skb->data + csstart, |
1198 | skb->len - csstart, 0); | 1156 | skb->len - csstart, 0); |
1199 | *((__sum16 *)(skb->data + csstart | 1157 | *((__sum16 *)(skb->data + csstart |
@@ -1311,6 +1269,21 @@ static const struct usb_device_id products[] = { | |||
1311 | USB_DEVICE(0x0424, 0x9909), | 1269 | USB_DEVICE(0x0424, 0x9909), |
1312 | .driver_info = (unsigned long) &smsc95xx_info, | 1270 | .driver_info = (unsigned long) &smsc95xx_info, |
1313 | }, | 1271 | }, |
1272 | { | ||
1273 | /* SMSC LAN9530 USB Ethernet Device */ | ||
1274 | USB_DEVICE(0x0424, 0x9530), | ||
1275 | .driver_info = (unsigned long) &smsc95xx_info, | ||
1276 | }, | ||
1277 | { | ||
1278 | /* SMSC LAN9730 USB Ethernet Device */ | ||
1279 | USB_DEVICE(0x0424, 0x9730), | ||
1280 | .driver_info = (unsigned long) &smsc95xx_info, | ||
1281 | }, | ||
1282 | { | ||
1283 | /* SMSC LAN89530 USB Ethernet Device */ | ||
1284 | USB_DEVICE(0x0424, 0x9E08), | ||
1285 | .driver_info = (unsigned long) &smsc95xx_info, | ||
1286 | }, | ||
1314 | { }, /* END */ | 1287 | { }, /* END */ |
1315 | }; | 1288 | }; |
1316 | MODULE_DEVICE_TABLE(usb, products); | 1289 | MODULE_DEVICE_TABLE(usb, products); |
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index ca7fc9df1ccf..ce395fe5de26 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/usb/usbnet.h> | 45 | #include <linux/usb/usbnet.h> |
46 | #include <linux/slab.h> | 46 | #include <linux/slab.h> |
47 | #include <linux/kernel.h> | 47 | #include <linux/kernel.h> |
48 | #include <linux/pm_runtime.h> | ||
48 | 49 | ||
49 | #define DRIVER_VERSION "22-Aug-2005" | 50 | #define DRIVER_VERSION "22-Aug-2005" |
50 | 51 | ||
@@ -108,7 +109,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) | |||
108 | 109 | ||
109 | /* take the first altsetting with in-bulk + out-bulk; | 110 | /* take the first altsetting with in-bulk + out-bulk; |
110 | * remember any status endpoint, just in case; | 111 | * remember any status endpoint, just in case; |
111 | * ignore other endpoints and altsetttings. | 112 | * ignore other endpoints and altsettings. |
112 | */ | 113 | */ |
113 | for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { | 114 | for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { |
114 | struct usb_host_endpoint *e; | 115 | struct usb_host_endpoint *e; |
@@ -386,18 +387,27 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) | |||
386 | static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) | 387 | static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) |
387 | { | 388 | { |
388 | if (dev->driver_info->rx_fixup && | 389 | if (dev->driver_info->rx_fixup && |
389 | !dev->driver_info->rx_fixup (dev, skb)) | 390 | !dev->driver_info->rx_fixup (dev, skb)) { |
390 | goto error; | 391 | /* With RX_ASSEMBLE, rx_fixup() must update counters */ |
392 | if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) | ||
393 | dev->net->stats.rx_errors++; | ||
394 | goto done; | ||
395 | } | ||
391 | // else network stack removes extra byte if we forced a short packet | 396 | // else network stack removes extra byte if we forced a short packet |
392 | 397 | ||
393 | if (skb->len) | 398 | if (skb->len) { |
394 | usbnet_skb_return (dev, skb); | 399 | /* all data was already cloned from skb inside the driver */ |
395 | else { | 400 | if (dev->driver_info->flags & FLAG_MULTI_PACKET) |
396 | netif_dbg(dev, rx_err, dev->net, "drop\n"); | 401 | dev_kfree_skb_any(skb); |
397 | error: | 402 | else |
398 | dev->net->stats.rx_errors++; | 403 | usbnet_skb_return(dev, skb); |
399 | skb_queue_tail (&dev->done, skb); | 404 | return; |
400 | } | 405 | } |
406 | |||
407 | netif_dbg(dev, rx_err, dev->net, "drop\n"); | ||
408 | dev->net->stats.rx_errors++; | ||
409 | done: | ||
410 | skb_queue_tail(&dev->done, skb); | ||
401 | } | 411 | } |
402 | 412 | ||
403 | /*-------------------------------------------------------------------------*/ | 413 | /*-------------------------------------------------------------------------*/ |
@@ -635,6 +645,7 @@ int usbnet_stop (struct net_device *net) | |||
635 | struct driver_info *info = dev->driver_info; | 645 | struct driver_info *info = dev->driver_info; |
636 | int retval; | 646 | int retval; |
637 | 647 | ||
648 | clear_bit(EVENT_DEV_OPEN, &dev->flags); | ||
638 | netif_stop_queue (net); | 649 | netif_stop_queue (net); |
639 | 650 | ||
640 | netif_info(dev, ifdown, dev->net, | 651 | netif_info(dev, ifdown, dev->net, |
@@ -726,6 +737,7 @@ int usbnet_open (struct net_device *net) | |||
726 | } | 737 | } |
727 | } | 738 | } |
728 | 739 | ||
740 | set_bit(EVENT_DEV_OPEN, &dev->flags); | ||
729 | netif_start_queue (net); | 741 | netif_start_queue (net); |
730 | netif_info(dev, ifup, dev->net, | 742 | netif_info(dev, ifup, dev->net, |
731 | "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", | 743 | "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", |
@@ -925,8 +937,10 @@ fail_halt: | |||
925 | if (urb != NULL) { | 937 | if (urb != NULL) { |
926 | clear_bit (EVENT_RX_MEMORY, &dev->flags); | 938 | clear_bit (EVENT_RX_MEMORY, &dev->flags); |
927 | status = usb_autopm_get_interface(dev->intf); | 939 | status = usb_autopm_get_interface(dev->intf); |
928 | if (status < 0) | 940 | if (status < 0) { |
941 | usb_free_urb(urb); | ||
929 | goto fail_lowmem; | 942 | goto fail_lowmem; |
943 | } | ||
930 | if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) | 944 | if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) |
931 | resched = 0; | 945 | resched = 0; |
932 | usb_autopm_put_interface(dev->intf); | 946 | usb_autopm_put_interface(dev->intf); |
@@ -970,7 +984,8 @@ static void tx_complete (struct urb *urb) | |||
970 | struct usbnet *dev = entry->dev; | 984 | struct usbnet *dev = entry->dev; |
971 | 985 | ||
972 | if (urb->status == 0) { | 986 | if (urb->status == 0) { |
973 | dev->net->stats.tx_packets++; | 987 | if (!(dev->driver_info->flags & FLAG_MULTI_PACKET)) |
988 | dev->net->stats.tx_packets++; | ||
974 | dev->net->stats.tx_bytes += entry->length; | 989 | dev->net->stats.tx_bytes += entry->length; |
975 | } else { | 990 | } else { |
976 | dev->net->stats.tx_errors++; | 991 | dev->net->stats.tx_errors++; |
@@ -1043,8 +1058,13 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, | |||
1043 | if (info->tx_fixup) { | 1058 | if (info->tx_fixup) { |
1044 | skb = info->tx_fixup (dev, skb, GFP_ATOMIC); | 1059 | skb = info->tx_fixup (dev, skb, GFP_ATOMIC); |
1045 | if (!skb) { | 1060 | if (!skb) { |
1046 | netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); | 1061 | if (netif_msg_tx_err(dev)) { |
1047 | goto drop; | 1062 | netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); |
1063 | goto drop; | ||
1064 | } else { | ||
1065 | /* cdc_ncm collected packet; waits for more */ | ||
1066 | goto not_drop; | ||
1067 | } | ||
1048 | } | 1068 | } |
1049 | } | 1069 | } |
1050 | length = skb->len; | 1070 | length = skb->len; |
@@ -1066,13 +1086,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, | |||
1066 | /* don't assume the hardware handles USB_ZERO_PACKET | 1086 | /* don't assume the hardware handles USB_ZERO_PACKET |
1067 | * NOTE: strictly conforming cdc-ether devices should expect | 1087 | * NOTE: strictly conforming cdc-ether devices should expect |
1068 | * the ZLP here, but ignore the one-byte packet. | 1088 | * the ZLP here, but ignore the one-byte packet. |
1089 | * NOTE2: CDC NCM specification is different from CDC ECM when | ||
1090 | * handling ZLP/short packets, so cdc_ncm driver will make short | ||
1091 | * packet itself if needed. | ||
1069 | */ | 1092 | */ |
1070 | if (length % dev->maxpacket == 0) { | 1093 | if (length % dev->maxpacket == 0) { |
1071 | if (!(info->flags & FLAG_SEND_ZLP)) { | 1094 | if (!(info->flags & FLAG_SEND_ZLP)) { |
1072 | urb->transfer_buffer_length++; | 1095 | if (!(info->flags & FLAG_MULTI_PACKET)) { |
1073 | if (skb_tailroom(skb)) { | 1096 | urb->transfer_buffer_length++; |
1074 | skb->data[skb->len] = 0; | 1097 | if (skb_tailroom(skb)) { |
1075 | __skb_put(skb, 1); | 1098 | skb->data[skb->len] = 0; |
1099 | __skb_put(skb, 1); | ||
1100 | } | ||
1076 | } | 1101 | } |
1077 | } else | 1102 | } else |
1078 | urb->transfer_flags |= URB_ZERO_PACKET; | 1103 | urb->transfer_flags |= URB_ZERO_PACKET; |
@@ -1121,6 +1146,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, | |||
1121 | netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); | 1146 | netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); |
1122 | drop: | 1147 | drop: |
1123 | dev->net->stats.tx_dropped++; | 1148 | dev->net->stats.tx_dropped++; |
1149 | not_drop: | ||
1124 | if (skb) | 1150 | if (skb) |
1125 | dev_kfree_skb_any (skb); | 1151 | dev_kfree_skb_any (skb); |
1126 | usb_free_urb (urb); | 1152 | usb_free_urb (urb); |
@@ -1230,12 +1256,14 @@ void usbnet_disconnect (struct usb_interface *intf) | |||
1230 | net = dev->net; | 1256 | net = dev->net; |
1231 | unregister_netdev (net); | 1257 | unregister_netdev (net); |
1232 | 1258 | ||
1233 | /* we don't hold rtnl here ... */ | 1259 | cancel_work_sync(&dev->kevent); |
1234 | flush_scheduled_work (); | ||
1235 | 1260 | ||
1236 | if (dev->driver_info->unbind) | 1261 | if (dev->driver_info->unbind) |
1237 | dev->driver_info->unbind (dev, intf); | 1262 | dev->driver_info->unbind (dev, intf); |
1238 | 1263 | ||
1264 | usb_kill_urb(dev->interrupt); | ||
1265 | usb_free_urb(dev->interrupt); | ||
1266 | |||
1239 | free_netdev(net); | 1267 | free_netdev(net); |
1240 | usb_put_dev (xdev); | 1268 | usb_put_dev (xdev); |
1241 | } | 1269 | } |
@@ -1273,6 +1301,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1273 | struct usb_device *xdev; | 1301 | struct usb_device *xdev; |
1274 | int status; | 1302 | int status; |
1275 | const char *name; | 1303 | const char *name; |
1304 | struct usb_driver *driver = to_usb_driver(udev->dev.driver); | ||
1305 | |||
1306 | /* usbnet already took usb runtime pm, so have to enable the feature | ||
1307 | * for usb interface, otherwise usb_autopm_get_interface may return | ||
1308 | * failure if USB_SUSPEND(RUNTIME_PM) is enabled. | ||
1309 | */ | ||
1310 | if (!driver->supports_autosuspend) { | ||
1311 | driver->supports_autosuspend = 1; | ||
1312 | pm_runtime_enable(&udev->dev); | ||
1313 | } | ||
1276 | 1314 | ||
1277 | name = udev->dev.driver->name; | 1315 | name = udev->dev.driver->name; |
1278 | info = (struct driver_info *) prod->driver_info; | 1316 | info = (struct driver_info *) prod->driver_info; |
@@ -1347,7 +1385,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) | |||
1347 | // else "eth%d" when there's reasonable doubt. userspace | 1385 | // else "eth%d" when there's reasonable doubt. userspace |
1348 | // can rename the link if it knows better. | 1386 | // can rename the link if it knows better. |
1349 | if ((dev->driver_info->flags & FLAG_ETHER) != 0 && | 1387 | if ((dev->driver_info->flags & FLAG_ETHER) != 0 && |
1350 | (net->dev_addr [0] & 0x02) == 0) | 1388 | ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || |
1389 | (net->dev_addr [0] & 0x02) == 0)) | ||
1351 | strcpy (net->name, "eth%d"); | 1390 | strcpy (net->name, "eth%d"); |
1352 | /* WLAN devices should always be named "wlan%d" */ | 1391 | /* WLAN devices should always be named "wlan%d" */ |
1353 | if ((dev->driver_info->flags & FLAG_WLAN) != 0) | 1392 | if ((dev->driver_info->flags & FLAG_WLAN) != 0) |
@@ -1464,6 +1503,10 @@ int usbnet_resume (struct usb_interface *intf) | |||
1464 | int retval; | 1503 | int retval; |
1465 | 1504 | ||
1466 | if (!--dev->suspend_count) { | 1505 | if (!--dev->suspend_count) { |
1506 | /* resume interrupt URBs */ | ||
1507 | if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) | ||
1508 | usb_submit_urb(dev->interrupt, GFP_NOIO); | ||
1509 | |||
1467 | spin_lock_irq(&dev->txq.lock); | 1510 | spin_lock_irq(&dev->txq.lock); |
1468 | while ((res = usb_get_from_anchor(&dev->deferred))) { | 1511 | while ((res = usb_get_from_anchor(&dev->deferred))) { |
1469 | 1512 | ||
@@ -1482,9 +1525,12 @@ int usbnet_resume (struct usb_interface *intf) | |||
1482 | smp_mb(); | 1525 | smp_mb(); |
1483 | clear_bit(EVENT_DEV_ASLEEP, &dev->flags); | 1526 | clear_bit(EVENT_DEV_ASLEEP, &dev->flags); |
1484 | spin_unlock_irq(&dev->txq.lock); | 1527 | spin_unlock_irq(&dev->txq.lock); |
1485 | if (!(dev->txq.qlen >= TX_QLEN(dev))) | 1528 | |
1486 | netif_start_queue(dev->net); | 1529 | if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { |
1487 | tasklet_schedule (&dev->bh); | 1530 | if (!(dev->txq.qlen >= TX_QLEN(dev))) |
1531 | netif_start_queue(dev->net); | ||
1532 | tasklet_schedule (&dev->bh); | ||
1533 | } | ||
1488 | } | 1534 | } |
1489 | return 0; | 1535 | return 0; |
1490 | } | 1536 | } |
@@ -1495,9 +1541,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume); | |||
1495 | 1541 | ||
1496 | static int __init usbnet_init(void) | 1542 | static int __init usbnet_init(void) |
1497 | { | 1543 | { |
1498 | /* compiler should optimize this out */ | 1544 | /* Compiler should optimize this out. */ |
1499 | BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) | 1545 | BUILD_BUG_ON( |
1500 | < sizeof (struct skb_data)); | 1546 | FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data)); |
1501 | 1547 | ||
1502 | random_ether_addr(node_id); | 1548 | random_ether_addr(node_id); |
1503 | return 0; | 1549 | return 0; |
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 3eb0b167b5b4..1a2234c20514 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c | |||
@@ -102,7 +102,7 @@ static int always_connected (struct usbnet *dev) | |||
102 | 102 | ||
103 | static const struct driver_info zaurus_sl5x00_info = { | 103 | static const struct driver_info zaurus_sl5x00_info = { |
104 | .description = "Sharp Zaurus SL-5x00", | 104 | .description = "Sharp Zaurus SL-5x00", |
105 | .flags = FLAG_FRAMING_Z, | 105 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, |
106 | .check_connect = always_connected, | 106 | .check_connect = always_connected, |
107 | .bind = zaurus_bind, | 107 | .bind = zaurus_bind, |
108 | .unbind = usbnet_cdc_unbind, | 108 | .unbind = usbnet_cdc_unbind, |
@@ -112,7 +112,7 @@ static const struct driver_info zaurus_sl5x00_info = { | |||
112 | 112 | ||
113 | static const struct driver_info zaurus_pxa_info = { | 113 | static const struct driver_info zaurus_pxa_info = { |
114 | .description = "Sharp Zaurus, PXA-2xx based", | 114 | .description = "Sharp Zaurus, PXA-2xx based", |
115 | .flags = FLAG_FRAMING_Z, | 115 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, |
116 | .check_connect = always_connected, | 116 | .check_connect = always_connected, |
117 | .bind = zaurus_bind, | 117 | .bind = zaurus_bind, |
118 | .unbind = usbnet_cdc_unbind, | 118 | .unbind = usbnet_cdc_unbind, |
@@ -122,7 +122,7 @@ static const struct driver_info zaurus_pxa_info = { | |||
122 | 122 | ||
123 | static const struct driver_info olympus_mxl_info = { | 123 | static const struct driver_info olympus_mxl_info = { |
124 | .description = "Olympus R1000", | 124 | .description = "Olympus R1000", |
125 | .flags = FLAG_FRAMING_Z, | 125 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, |
126 | .check_connect = always_connected, | 126 | .check_connect = always_connected, |
127 | .bind = zaurus_bind, | 127 | .bind = zaurus_bind, |
128 | .unbind = usbnet_cdc_unbind, | 128 | .unbind = usbnet_cdc_unbind, |
@@ -258,7 +258,7 @@ bad_desc: | |||
258 | 258 | ||
259 | static const struct driver_info bogus_mdlm_info = { | 259 | static const struct driver_info bogus_mdlm_info = { |
260 | .description = "pseudo-MDLM (BLAN) device", | 260 | .description = "pseudo-MDLM (BLAN) device", |
261 | .flags = FLAG_FRAMING_Z, | 261 | .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, |
262 | .check_connect = always_connected, | 262 | .check_connect = always_connected, |
263 | .tx_fixup = zaurus_tx_fixup, | 263 | .tx_fixup = zaurus_tx_fixup, |
264 | .bind = blan_mdlm_bind, | 264 | .bind = blan_mdlm_bind, |
@@ -331,17 +331,7 @@ static const struct usb_device_id products [] = { | |||
331 | ZAURUS_MASTER_INTERFACE, | 331 | ZAURUS_MASTER_INTERFACE, |
332 | .driver_info = ZAURUS_PXA_INFO, | 332 | .driver_info = ZAURUS_PXA_INFO, |
333 | }, | 333 | }, |
334 | |||
335 | |||
336 | /* At least some of the newest PXA units have very different lies about | ||
337 | * their standards support: they claim to be cell phones offering | ||
338 | * direct access to their radios! (No, they don't conform to CDC MDLM.) | ||
339 | */ | ||
340 | { | 334 | { |
341 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, | ||
342 | USB_CDC_PROTO_NONE), | ||
343 | .driver_info = (unsigned long) &bogus_mdlm_info, | ||
344 | }, { | ||
345 | /* Motorola MOTOMAGX phones */ | 335 | /* Motorola MOTOMAGX phones */ |
346 | USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM, | 336 | USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM, |
347 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), | 337 | USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), |