int51x1.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2009 Peter Holik
  4. *
  5. * Intellon usb PLC (Powerline Communications) usb net driver
  6. *
  7. * https://web.archive.org/web/20101025091240id_/http://www.tandel.be/downloads/INT51X1_Datasheet.pdf
  8. *
  9. * Based on the work of Jan 'RedBully' Seiffert
  10. */
  11. #include <linux/module.h>
  12. #include <linux/ctype.h>
  13. #include <linux/netdevice.h>
  14. #include <linux/etherdevice.h>
  15. #include <linux/ethtool.h>
  16. #include <linux/slab.h>
  17. #include <linux/mii.h>
  18. #include <linux/usb.h>
  19. #include <linux/usb/usbnet.h>
  20. #define INT51X1_VENDOR_ID 0x09e1
  21. #define INT51X1_PRODUCT_ID 0x5121
  22. #define INT51X1_HEADER_SIZE 2 /* 2 byte header */
  23. static int int51x1_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  24. {
  25. int len;
  26. if (!(pskb_may_pull(skb, INT51X1_HEADER_SIZE))) {
  27. netdev_err(dev->net, "unexpected tiny rx frame\n");
  28. return 0;
  29. }
  30. len = le16_to_cpu(*(__le16 *)&skb->data[skb->len - 2]);
  31. skb_trim(skb, len);
  32. return 1;
  33. }
  34. static struct sk_buff *int51x1_tx_fixup(struct usbnet *dev,
  35. struct sk_buff *skb, gfp_t flags)
  36. {
  37. int pack_len = skb->len;
  38. int pack_with_header_len = pack_len + INT51X1_HEADER_SIZE;
  39. int headroom = skb_headroom(skb);
  40. int tailroom = skb_tailroom(skb);
  41. int need_tail = 0;
  42. __le16 *len;
  43. /* if packet and our header is smaller than 64 pad to 64 (+ ZLP) */
  44. if ((pack_with_header_len) < dev->maxpacket)
  45. need_tail = dev->maxpacket - pack_with_header_len + 1;
  46. /*
  47. * usbnet would send a ZLP if packetlength mod urbsize == 0 for us,
  48. * but we need to know ourself, because this would add to the length
  49. * we send down to the device...
  50. */
  51. else if (!(pack_with_header_len % dev->maxpacket))
  52. need_tail = 1;
  53. if (!skb_cloned(skb) &&
  54. (headroom + tailroom >= need_tail + INT51X1_HEADER_SIZE)) {
  55. if (headroom < INT51X1_HEADER_SIZE || tailroom < need_tail) {
  56. skb->data = memmove(skb->head + INT51X1_HEADER_SIZE,
  57. skb->data, skb->len);
  58. skb_set_tail_pointer(skb, skb->len);
  59. }
  60. } else {
  61. struct sk_buff *skb2;
  62. skb2 = skb_copy_expand(skb,
  63. INT51X1_HEADER_SIZE,
  64. need_tail,
  65. flags);
  66. dev_kfree_skb_any(skb);
  67. if (!skb2)
  68. return NULL;
  69. skb = skb2;
  70. }
  71. pack_len += need_tail;
  72. pack_len &= 0x07ff;
  73. len = __skb_push(skb, INT51X1_HEADER_SIZE);
  74. *len = cpu_to_le16(pack_len);
  75. if(need_tail)
  76. __skb_put_zero(skb, need_tail);
  77. return skb;
  78. }
  79. static const struct net_device_ops int51x1_netdev_ops = {
  80. .ndo_open = usbnet_open,
  81. .ndo_stop = usbnet_stop,
  82. .ndo_start_xmit = usbnet_start_xmit,
  83. .ndo_tx_timeout = usbnet_tx_timeout,
  84. .ndo_change_mtu = usbnet_change_mtu,
  85. .ndo_get_stats64 = dev_get_tstats64,
  86. .ndo_set_mac_address = eth_mac_addr,
  87. .ndo_validate_addr = eth_validate_addr,
  88. .ndo_set_rx_mode = usbnet_set_rx_mode,
  89. };
  90. static int int51x1_bind(struct usbnet *dev, struct usb_interface *intf)
  91. {
  92. int status = usbnet_get_ethernet_addr(dev, 3);
  93. if (status)
  94. return status;
  95. dev->net->hard_header_len += INT51X1_HEADER_SIZE;
  96. dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
  97. dev->net->netdev_ops = &int51x1_netdev_ops;
  98. return usbnet_get_endpoints(dev, intf);
  99. }
  100. static const struct driver_info int51x1_info = {
  101. .description = "Intellon usb powerline adapter",
  102. .bind = int51x1_bind,
  103. .rx_fixup = int51x1_rx_fixup,
  104. .tx_fixup = int51x1_tx_fixup,
  105. .set_rx_mode = usbnet_cdc_update_filter,
  106. .in = 1,
  107. .out = 2,
  108. .flags = FLAG_ETHER,
  109. };
  110. static const struct usb_device_id products[] = {
  111. {
  112. USB_DEVICE(INT51X1_VENDOR_ID, INT51X1_PRODUCT_ID),
  113. .driver_info = (unsigned long) &int51x1_info,
  114. },
  115. {},
  116. };
  117. MODULE_DEVICE_TABLE(usb, products);
  118. static struct usb_driver int51x1_driver = {
  119. .name = "int51x1",
  120. .id_table = products,
  121. .probe = usbnet_probe,
  122. .disconnect = usbnet_disconnect,
  123. .suspend = usbnet_suspend,
  124. .resume = usbnet_resume,
  125. .disable_hub_initiated_lpm = 1,
  126. };
  127. module_usb_driver(int51x1_driver);
  128. MODULE_AUTHOR("Peter Holik");
  129. MODULE_DESCRIPTION("Intellon usb powerline adapter");
  130. MODULE_LICENSE("GPL");