brintos

brintos / linux-shallow public Read only

0
0
Text · 13.4 KiB · 5d4a1fd Raw
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