523 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Net1080 based USB host-to-host cables4 * Copyright (C) 2000-2005 by David Brownell5 */6 7// #define DEBUG // error path messages, extra info8// #define VERBOSE // more; success messages9 10#include <linux/module.h>11#include <linux/netdevice.h>12#include <linux/etherdevice.h>13#include <linux/ethtool.h>14#include <linux/workqueue.h>15#include <linux/mii.h>16#include <linux/usb.h>17#include <linux/usb/usbnet.h>18#include <linux/slab.h>19 20#include <linux/unaligned.h>21 22 23/*24 * Netchip 1080 driver ... http://www.netchip.com25 * (Sept 2004: End-of-life announcement has been sent.)26 * Used in (some) LapLink cables27 */28 29#define frame_errors data[1]30 31/*32 * NetChip framing of ethernet packets, supporting additional error33 * checks for links that may drop bulk packets from inside messages.34 * Odd USB length == always short read for last usb packet.35 * - nc_header36 * - Ethernet header (14 bytes)37 * - payload38 * - (optional padding byte, if needed so length becomes odd)39 * - nc_trailer40 *41 * This framing is to be avoided for non-NetChip devices.42 */43 44struct nc_header { // packed:45 __le16 hdr_len; // sizeof nc_header (LE, all)46 __le16 packet_len; // payload size (including ethhdr)47 __le16 packet_id; // detects dropped packets48#define MIN_HEADER 649 50 // all else is optional, and must start with:51 // __le16 vendorId; // from usb-if52 // __le16 productId;53} __packed;54 55#define PAD_BYTE ((unsigned char)0xAC)56 57struct nc_trailer {58 __le16 packet_id;59} __packed;60 61// packets may use FLAG_FRAMING_NC and optional pad62#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \63 + sizeof (struct ethhdr) \64 + (mtu) \65 + 1 \66 + sizeof (struct nc_trailer))67 68#define MIN_FRAMED FRAMED_SIZE(0)69 70/* packets _could_ be up to 64KB... */71#define NC_MAX_PACKET 3276772 73 74/*75 * Zero means no timeout; else, how long a 64 byte bulk packet may be queued76 * before the hardware drops it. If that's done, the driver will need to77 * frame network packets to guard against the dropped USB packets. The win3278 * driver sets this for both sides of the link.79 */80#define NC_READ_TTL_MS ((u8)255) // ms81 82/*83 * We ignore most registers and EEPROM contents.84 */85#define REG_USBCTL ((u8)0x04)86#define REG_TTL ((u8)0x10)87#define REG_STATUS ((u8)0x11)88 89/*90 * Vendor specific requests to read/write data91 */92#define REQUEST_REGISTER ((u8)0x10)93#define REQUEST_EEPROM ((u8)0x11)94 95static int96nc_vendor_read(struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)97{98 int status = usbnet_read_cmd(dev, req,99 USB_DIR_IN | USB_TYPE_VENDOR |100 USB_RECIP_DEVICE,101 0, regnum, retval_ptr,102 sizeof *retval_ptr);103 if (status > 0)104 status = 0;105 if (!status)106 le16_to_cpus(retval_ptr);107 return status;108}109 110static inline int111nc_register_read(struct usbnet *dev, u8 regnum, u16 *retval_ptr)112{113 return nc_vendor_read(dev, REQUEST_REGISTER, regnum, retval_ptr);114}115 116static void117nc_vendor_write(struct usbnet *dev, u8 req, u8 regnum, u16 value)118{119 usbnet_write_cmd(dev, req,120 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,121 value, regnum, NULL, 0);122}123 124static inline void125nc_register_write(struct usbnet *dev, u8 regnum, u16 value)126{127 nc_vendor_write(dev, REQUEST_REGISTER, regnum, value);128}129 130 131#if 0132static void nc_dump_registers(struct usbnet *dev)133{134 u8 reg;135 u16 *vp = kmalloc(sizeof (u16));136 137 if (!vp)138 return;139 140 netdev_dbg(dev->net, "registers:\n");141 for (reg = 0; reg < 0x20; reg++) {142 int retval;143 144 // reading some registers is trouble145 if (reg >= 0x08 && reg <= 0xf)146 continue;147 if (reg >= 0x12 && reg <= 0x1e)148 continue;149 150 retval = nc_register_read(dev, reg, vp);151 if (retval < 0)152 netdev_dbg(dev->net, "reg [0x%x] ==> error %d\n",153 reg, retval);154 else155 netdev_dbg(dev->net, "reg [0x%x] = 0x%x\n", reg, *vp);156 }157 kfree(vp);158}159#endif160 161 162/*-------------------------------------------------------------------------*/163 164/*165 * Control register166 */167 168#define USBCTL_WRITABLE_MASK 0x1f0f169// bits 15-13 reserved, r/o170#define USBCTL_ENABLE_LANG (1 << 12)171#define USBCTL_ENABLE_MFGR (1 << 11)172#define USBCTL_ENABLE_PROD (1 << 10)173#define USBCTL_ENABLE_SERIAL (1 << 9)174#define USBCTL_ENABLE_DEFAULTS (1 << 8)175// bits 7-4 reserved, r/o176#define USBCTL_FLUSH_OTHER (1 << 3)177#define USBCTL_FLUSH_THIS (1 << 2)178#define USBCTL_DISCONN_OTHER (1 << 1)179#define USBCTL_DISCONN_THIS (1 << 0)180 181static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl)182{183 netif_dbg(dev, link, dev->net,184 "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s; this%s%s; other%s%s; r/o 0x%x\n",185 dev->udev->bus->bus_name, dev->udev->devpath,186 usbctl,187 (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",188 (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",189 (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",190 (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",191 (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",192 193 (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",194 (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",195 196 (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",197 (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",198 199 usbctl & ~USBCTL_WRITABLE_MASK);200}201 202/*-------------------------------------------------------------------------*/203 204/*205 * Status register206 */207 208#define STATUS_PORT_A (1 << 15)209 210#define STATUS_CONN_OTHER (1 << 14)211#define STATUS_SUSPEND_OTHER (1 << 13)212#define STATUS_MAILBOX_OTHER (1 << 12)213#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03)214 215#define STATUS_CONN_THIS (1 << 6)216#define STATUS_SUSPEND_THIS (1 << 5)217#define STATUS_MAILBOX_THIS (1 << 4)218#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03)219 220#define STATUS_UNSPEC_MASK 0x0c8c221#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK))222 223 224static inline void nc_dump_status(struct usbnet *dev, u16 status)225{226 netif_dbg(dev, link, dev->net,227 "net1080 %s-%s status 0x%x: this (%c) PKT=%d%s%s%s; other PKT=%d%s%s%s; unspec 0x%x\n",228 dev->udev->bus->bus_name, dev->udev->devpath,229 status,230 231 // XXX the packet counts don't seem right232 // (1 at reset, not 0); maybe UNSPEC too233 234 (status & STATUS_PORT_A) ? 'A' : 'B',235 STATUS_PACKETS_THIS(status),236 (status & STATUS_CONN_THIS) ? " CON" : "",237 (status & STATUS_SUSPEND_THIS) ? " SUS" : "",238 (status & STATUS_MAILBOX_THIS) ? " MBOX" : "",239 240 STATUS_PACKETS_OTHER(status),241 (status & STATUS_CONN_OTHER) ? " CON" : "",242 (status & STATUS_SUSPEND_OTHER) ? " SUS" : "",243 (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",244 245 status & STATUS_UNSPEC_MASK);246}247 248/*-------------------------------------------------------------------------*/249 250/*251 * TTL register252 */253 254#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8))255#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this))))256 257/*-------------------------------------------------------------------------*/258 259static int net1080_reset(struct usbnet *dev)260{261 u16 usbctl, status, ttl;262 u16 vp;263 int retval;264 265 // nc_dump_registers(dev);266 267 if ((retval = nc_register_read(dev, REG_STATUS, &vp)) < 0) {268 netdev_dbg(dev->net, "can't read %s-%s status: %d\n",269 dev->udev->bus->bus_name, dev->udev->devpath, retval);270 goto done;271 }272 status = vp;273 nc_dump_status(dev, status);274 275 if ((retval = nc_register_read(dev, REG_USBCTL, &vp)) < 0) {276 netdev_dbg(dev->net, "can't read USBCTL, %d\n", retval);277 goto done;278 }279 usbctl = vp;280 nc_dump_usbctl(dev, usbctl);281 282 nc_register_write(dev, REG_USBCTL,283 USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);284 285 if ((retval = nc_register_read(dev, REG_TTL, &vp)) < 0) {286 netdev_dbg(dev->net, "can't read TTL, %d\n", retval);287 goto done;288 }289 ttl = vp;290 291 nc_register_write(dev, REG_TTL,292 MK_TTL(NC_READ_TTL_MS, TTL_OTHER(ttl)) );293 netdev_dbg(dev->net, "assigned TTL, %d ms\n", NC_READ_TTL_MS);294 295 netif_info(dev, link, dev->net, "port %c, peer %sconnected\n",296 (status & STATUS_PORT_A) ? 'A' : 'B',297 (status & STATUS_CONN_OTHER) ? "" : "dis");298 retval = 0;299 300done:301 return retval;302}303 304static int net1080_check_connect(struct usbnet *dev)305{306 int retval;307 u16 status;308 u16 vp;309 310 retval = nc_register_read(dev, REG_STATUS, &vp);311 status = vp;312 if (retval != 0) {313 netdev_dbg(dev->net, "net1080_check_conn read - %d\n", retval);314 return retval;315 }316 if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)317 return -ENOLINK;318 return 0;319}320 321static void nc_ensure_sync(struct usbnet *dev)322{323 if (++dev->frame_errors <= 5)324 return;325 326 if (usbnet_write_cmd_async(dev, REQUEST_REGISTER,327 USB_DIR_OUT | USB_TYPE_VENDOR |328 USB_RECIP_DEVICE,329 USBCTL_FLUSH_THIS |330 USBCTL_FLUSH_OTHER,331 REG_USBCTL, NULL, 0))332 return;333 334 netif_dbg(dev, rx_err, dev->net,335 "flush net1080; too many framing errors\n");336 dev->frame_errors = 0;337}338 339static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)340{341 struct nc_header *header;342 struct nc_trailer *trailer;343 u16 hdr_len, packet_len;344 345 /* This check is no longer done by usbnet */346 if (skb->len < dev->net->hard_header_len)347 return 0;348 349 if (!(skb->len & 0x01)) {350 netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",351 skb->len, dev->net->hard_header_len, dev->hard_mtu,352 dev->net->mtu);353 dev->net->stats.rx_frame_errors++;354 nc_ensure_sync(dev);355 return 0;356 }357 358 header = (struct nc_header *) skb->data;359 hdr_len = le16_to_cpup(&header->hdr_len);360 packet_len = le16_to_cpup(&header->packet_len);361 if (FRAMED_SIZE(packet_len) > NC_MAX_PACKET) {362 dev->net->stats.rx_frame_errors++;363 netdev_dbg(dev->net, "packet too big, %d\n", packet_len);364 nc_ensure_sync(dev);365 return 0;366 } else if (hdr_len < MIN_HEADER) {367 dev->net->stats.rx_frame_errors++;368 netdev_dbg(dev->net, "header too short, %d\n", hdr_len);369 nc_ensure_sync(dev);370 return 0;371 } else if (hdr_len > MIN_HEADER) {372 // out of band data for us?373 netdev_dbg(dev->net, "header OOB, %d bytes\n", hdr_len - MIN_HEADER);374 nc_ensure_sync(dev);375 // switch (vendor/product ids) { ... }376 }377 skb_pull(skb, hdr_len);378 379 trailer = (struct nc_trailer *)380 (skb->data + skb->len - sizeof *trailer);381 skb_trim(skb, skb->len - sizeof *trailer);382 383 if ((packet_len & 0x01) == 0) {384 if (skb->data [packet_len] != PAD_BYTE) {385 dev->net->stats.rx_frame_errors++;386 netdev_dbg(dev->net, "bad pad\n");387 return 0;388 }389 skb_trim(skb, skb->len - 1);390 }391 if (skb->len != packet_len) {392 dev->net->stats.rx_frame_errors++;393 netdev_dbg(dev->net, "bad packet len %d (expected %d)\n",394 skb->len, packet_len);395 nc_ensure_sync(dev);396 return 0;397 }398 if (header->packet_id != get_unaligned(&trailer->packet_id)) {399 dev->net->stats.rx_fifo_errors++;400 netdev_dbg(dev->net, "(2+ dropped) rx packet_id mismatch 0x%x 0x%x\n",401 le16_to_cpu(header->packet_id),402 le16_to_cpu(trailer->packet_id));403 return 0;404 }405#if 0406 netdev_dbg(dev->net, "frame <rx h %d p %d id %d\n", header->hdr_len,407 header->packet_len, header->packet_id);408#endif409 dev->frame_errors = 0;410 return 1;411}412 413static struct sk_buff *414net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)415{416 struct sk_buff *skb2;417 struct nc_header *header = NULL;418 struct nc_trailer *trailer = NULL;419 int padlen = sizeof (struct nc_trailer);420 int len = skb->len;421 422 if (!((len + padlen + sizeof (struct nc_header)) & 0x01))423 padlen++;424 if (!skb_cloned(skb)) {425 int headroom = skb_headroom(skb);426 int tailroom = skb_tailroom(skb);427 428 if (padlen <= tailroom &&429 sizeof(struct nc_header) <= headroom)430 /* There's enough head and tail room */431 goto encapsulate;432 433 if ((sizeof (struct nc_header) + padlen) <434 (headroom + tailroom)) {435 /* There's enough total room, so just readjust */436 skb->data = memmove(skb->head437 + sizeof (struct nc_header),438 skb->data, skb->len);439 skb_set_tail_pointer(skb, len);440 goto encapsulate;441 }442 }443 444 /* Create a new skb to use with the correct size */445 skb2 = skb_copy_expand(skb,446 sizeof (struct nc_header),447 padlen,448 flags);449 dev_kfree_skb_any(skb);450 if (!skb2)451 return skb2;452 skb = skb2;453 454encapsulate:455 /* header first */456 header = skb_push(skb, sizeof *header);457 header->hdr_len = cpu_to_le16(sizeof (*header));458 header->packet_len = cpu_to_le16(len);459 header->packet_id = cpu_to_le16((u16)dev->xid++);460 461 /* maybe pad; then trailer */462 if (!((skb->len + sizeof *trailer) & 0x01))463 skb_put_u8(skb, PAD_BYTE);464 trailer = skb_put(skb, sizeof *trailer);465 put_unaligned(header->packet_id, &trailer->packet_id);466#if 0467 netdev_dbg(dev->net, "frame >tx h %d p %d id %d\n",468 header->hdr_len, header->packet_len,469 header->packet_id);470#endif471 return skb;472}473 474static int net1080_bind(struct usbnet *dev, struct usb_interface *intf)475{476 unsigned extra = sizeof (struct nc_header)477 + 1478 + sizeof (struct nc_trailer);479 480 dev->net->hard_header_len += extra;481 dev->rx_urb_size = dev->net->hard_header_len + dev->net->mtu;482 dev->hard_mtu = NC_MAX_PACKET;483 return usbnet_get_endpoints (dev, intf);484}485 486static const struct driver_info net1080_info = {487 .description = "NetChip TurboCONNECT",488 .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC,489 .bind = net1080_bind,490 .reset = net1080_reset,491 .check_connect = net1080_check_connect,492 .rx_fixup = net1080_rx_fixup,493 .tx_fixup = net1080_tx_fixup,494};495 496static const struct usb_device_id products [] = {497{498 USB_DEVICE(0x0525, 0x1080), // NetChip ref design499 .driver_info = (unsigned long) &net1080_info,500}, {501 USB_DEVICE(0x06D0, 0x0622), // Laplink Gold502 .driver_info = (unsigned long) &net1080_info,503},504 { }, // END505};506MODULE_DEVICE_TABLE(usb, products);507 508static struct usb_driver net1080_driver = {509 .name = "net1080",510 .id_table = products,511 .probe = usbnet_probe,512 .disconnect = usbnet_disconnect,513 .suspend = usbnet_suspend,514 .resume = usbnet_resume,515 .disable_hub_initiated_lpm = 1,516};517 518module_usb_driver(net1080_driver);519 520MODULE_AUTHOR("David Brownell");521MODULE_DESCRIPTION("NetChip 1080 based USB Host-to-Host Links");522MODULE_LICENSE("GPL");523