diff options
Diffstat (limited to 'drivers/net/usb/dm9601.c')
-rw-r--r-- | drivers/net/usb/dm9601.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index c6867f926cff..e80219877730 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices | 2 | * Davicom DM96xx USB 10/100Mbps ethernet devices |
3 | * | 3 | * |
4 | * Peter Korsgaard <jacmet@sunsite.dk> | 4 | * Peter Korsgaard <jacmet@sunsite.dk> |
5 | * | 5 | * |
@@ -364,7 +364,12 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) | |||
364 | dev->net->ethtool_ops = &dm9601_ethtool_ops; | 364 | dev->net->ethtool_ops = &dm9601_ethtool_ops; |
365 | dev->net->hard_header_len += DM_TX_OVERHEAD; | 365 | dev->net->hard_header_len += DM_TX_OVERHEAD; |
366 | dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; | 366 | dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; |
367 | dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD; | 367 | |
368 | /* dm9620/21a require room for 4 byte padding, even in dm9601 | ||
369 | * mode, so we need +1 to be able to receive full size | ||
370 | * ethernet frames. | ||
371 | */ | ||
372 | dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1; | ||
368 | 373 | ||
369 | dev->mii.dev = dev->net; | 374 | dev->mii.dev = dev->net; |
370 | dev->mii.mdio_read = dm9601_mdio_read; | 375 | dev->mii.mdio_read = dm9601_mdio_read; |
@@ -468,7 +473,7 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | |||
468 | static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | 473 | static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
469 | gfp_t flags) | 474 | gfp_t flags) |
470 | { | 475 | { |
471 | int len; | 476 | int len, pad; |
472 | 477 | ||
473 | /* format: | 478 | /* format: |
474 | b1: packet length low | 479 | b1: packet length low |
@@ -476,12 +481,23 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
476 | b3..n: packet data | 481 | b3..n: packet data |
477 | */ | 482 | */ |
478 | 483 | ||
479 | len = skb->len; | 484 | len = skb->len + DM_TX_OVERHEAD; |
480 | 485 | ||
481 | if (skb_headroom(skb) < DM_TX_OVERHEAD) { | 486 | /* workaround for dm962x errata with tx fifo getting out of |
487 | * sync if a USB bulk transfer retry happens right after a | ||
488 | * packet with odd / maxpacket length by adding up to 3 bytes | ||
489 | * padding. | ||
490 | */ | ||
491 | while ((len & 1) || !(len % dev->maxpacket)) | ||
492 | len++; | ||
493 | |||
494 | len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */ | ||
495 | pad = len - skb->len; | ||
496 | |||
497 | if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) { | ||
482 | struct sk_buff *skb2; | 498 | struct sk_buff *skb2; |
483 | 499 | ||
484 | skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); | 500 | skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags); |
485 | dev_kfree_skb_any(skb); | 501 | dev_kfree_skb_any(skb); |
486 | skb = skb2; | 502 | skb = skb2; |
487 | if (!skb) | 503 | if (!skb) |
@@ -490,10 +506,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, | |||
490 | 506 | ||
491 | __skb_push(skb, DM_TX_OVERHEAD); | 507 | __skb_push(skb, DM_TX_OVERHEAD); |
492 | 508 | ||
493 | /* usbnet adds padding if length is a multiple of packet size | 509 | if (pad) { |
494 | if so, adjust length value in header */ | 510 | memset(skb->data + skb->len, 0, pad); |
495 | if ((skb->len % dev->maxpacket) == 0) | 511 | __skb_put(skb, pad); |
496 | len++; | 512 | } |
497 | 513 | ||
498 | skb->data[0] = len; | 514 | skb->data[0] = len; |
499 | skb->data[1] = len >> 8; | 515 | skb->data[1] = len >> 8; |
@@ -543,7 +559,7 @@ static int dm9601_link_reset(struct usbnet *dev) | |||
543 | } | 559 | } |
544 | 560 | ||
545 | static const struct driver_info dm9601_info = { | 561 | static const struct driver_info dm9601_info = { |
546 | .description = "Davicom DM9601 USB Ethernet", | 562 | .description = "Davicom DM96xx USB 10/100 Ethernet", |
547 | .flags = FLAG_ETHER | FLAG_LINK_INTR, | 563 | .flags = FLAG_ETHER | FLAG_LINK_INTR, |
548 | .bind = dm9601_bind, | 564 | .bind = dm9601_bind, |
549 | .rx_fixup = dm9601_rx_fixup, | 565 | .rx_fixup = dm9601_rx_fixup, |
@@ -594,6 +610,22 @@ static const struct usb_device_id products[] = { | |||
594 | USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */ | 610 | USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */ |
595 | .driver_info = (unsigned long)&dm9601_info, | 611 | .driver_info = (unsigned long)&dm9601_info, |
596 | }, | 612 | }, |
613 | { | ||
614 | USB_DEVICE(0x0a46, 0x9621), /* DM9621A USB to Fast Ethernet Adapter */ | ||
615 | .driver_info = (unsigned long)&dm9601_info, | ||
616 | }, | ||
617 | { | ||
618 | USB_DEVICE(0x0a46, 0x9622), /* DM9622 USB to Fast Ethernet Adapter */ | ||
619 | .driver_info = (unsigned long)&dm9601_info, | ||
620 | }, | ||
621 | { | ||
622 | USB_DEVICE(0x0a46, 0x0269), /* DM962OA USB to Fast Ethernet Adapter */ | ||
623 | .driver_info = (unsigned long)&dm9601_info, | ||
624 | }, | ||
625 | { | ||
626 | USB_DEVICE(0x0a46, 0x1269), /* DM9621A USB to Fast Ethernet Adapter */ | ||
627 | .driver_info = (unsigned long)&dm9601_info, | ||
628 | }, | ||
597 | {}, // END | 629 | {}, // END |
598 | }; | 630 | }; |
599 | 631 | ||
@@ -612,5 +644,5 @@ static struct usb_driver dm9601_driver = { | |||
612 | module_usb_driver(dm9601_driver); | 644 | module_usb_driver(dm9601_driver); |
613 | 645 | ||
614 | MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); | 646 | MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); |
615 | MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); | 647 | MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices"); |
616 | MODULE_LICENSE("GPL"); | 648 | MODULE_LICENSE("GPL"); |