147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell/*
247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * GeneSys GL620USB-A based links
347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * This program is free software; you can redistribute it and/or modify
747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * it under the terms of the GNU General Public License as published by
847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * the Free Software Foundation; either version 2 of the License, or
947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * (at your option) any later version.
1047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
1147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * This program is distributed in the hope that it will be useful,
1247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * but WITHOUT ANY WARRANTY; without even the implied warranty of
1347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * GNU General Public License for more details.
1547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
1647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * You should have received a copy of the GNU General Public License
1747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * along with this program; if not, write to the Free Software
1847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell */
2047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
2147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// #define	DEBUG			// error path messages, extra info
2247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// #define	VERBOSE			// more; success messages
2347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
2447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/module.h>
2547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/init.h>
2647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/netdevice.h>
2747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/etherdevice.h>
2847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/ethtool.h>
2947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/workqueue.h>
3047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/mii.h>
3147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#include <linux/usb.h>
323692e94f1559523b84a5a0e65929ee84b276e83fJussi Kivilinna#include <linux/usb/usbnet.h>
335a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
3447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
3547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
3647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell/*
3747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * GeneSys GL620USB-A (www.genesyslogic.com.tw)
3847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
3947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * ... should partially interop with the Win32 driver for this hardware.
4047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * The GeneSys docs imply there's some NDIS issue motivating this framing.
4147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
4247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * Some info from GeneSys:
4347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
4447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *    (Some cables, like the BAFO-100c, use the half duplex version.)
4547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *  - For the full duplex model, the low bit of the version code says
4647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *    which side is which ("left/right").
4747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *  - For the half duplex type, a control/interrupt handshake settles
4847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *    the transfer direction.  (That's disabled here, partially coded.)
4947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *    A control URB would block until other side writes an interrupt.
5047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell *
5147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
5247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
5347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell */
5447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
5547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// control msg write command
5647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GENELINK_CONNECT_WRITE			0xF0
5747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// interrupt pipe index
5847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GENELINK_INTERRUPT_PIPE			0x03
5947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// interrupt read buffer size
6047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define INTERRUPT_BUFSIZE			0x08
6147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// interrupt pipe interval value
6247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GENELINK_INTERRUPT_INTERVAL		0x10
6347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// max transmit packet number per transmit
6447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GL_MAX_TRANSMIT_PACKETS			32
6547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// max packet length
6647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GL_MAX_PACKET_LEN			1514
6747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell// max receive buffer size
6847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#define GL_RCV_BUF_SIZE		\
6947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
7047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
7147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstruct gl_packet {
7253ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	__le32		packet_length;
7347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	char		packet_data [1];
7447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell};
7547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
7647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstruct gl_header {
7753ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	__le32			packet_count;
7847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	struct gl_packet	packets;
7947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell};
8047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
8147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
8247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell{
8347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	struct gl_header	*header;
8447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	struct gl_packet	*packet;
8547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	struct sk_buff		*gl_skb;
8647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	u32			size;
8753ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	u32			count;
8847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
8947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	header = (struct gl_header *) skb->data;
9047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
9147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// get the packet count of the received skb
9253ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	count = le32_to_cpu(header->packet_count);
9353ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	if (count > GL_MAX_TRANSMIT_PACKETS) {
9453ebb3b8264a77b6214f7a405300de8c24a12554Al Viro		dbg("genelink: invalid received packet count %u", count);
9547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		return 0;
9647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	}
9747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
9847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// set the current packet pointer to the first packet
9947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	packet = &header->packets;
10047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
10147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// decrement the length for the packet count size 4 bytes
10247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	skb_pull(skb, 4);
10347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
10453ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	while (count > 1) {
10547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		// get the packet length
10647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		size = le32_to_cpu(packet->packet_length);
10747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
10847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		// this may be a broken packet
10947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		if (size > GL_MAX_PACKET_LEN) {
11047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			dbg("genelink: invalid rx length %d", size);
11147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			return 0;
11247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		}
11347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
11447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		// allocate the skb for the individual packet
11547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		gl_skb = alloc_skb(size, GFP_ATOMIC);
11647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		if (gl_skb) {
11747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
11847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			// copy the packet data to the new skb
11947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			memcpy(skb_put(gl_skb, size),
12047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell					packet->packet_data, size);
12147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			usbnet_skb_return(dev, gl_skb);
12247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		}
12347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
12447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		// advance to the next packet
12553ebb3b8264a77b6214f7a405300de8c24a12554Al Viro		packet = (struct gl_packet *)&packet->packet_data[size];
12653ebb3b8264a77b6214f7a405300de8c24a12554Al Viro		count--;
12747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
12847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		// shift the data pointer to the next gl_packet
12947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		skb_pull(skb, size + 4);
13047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	}
13147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
13247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// skip the packet length field 4 bytes
13347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	skb_pull(skb, 4);
13447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
13547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	if (skb->len > GL_MAX_PACKET_LEN) {
13647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		dbg("genelink: invalid rx length %d", skb->len);
13747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		return 0;
13847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	}
13947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	return 1;
14047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell}
14147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
14247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic struct sk_buff *
14355016f10e31bb15b85d8c500f979dfdceb37d548Al Virogenelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
14447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell{
14547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	int 	padlen;
14647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	int	length = skb->len;
14747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	int	headroom = skb_headroom(skb);
14847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	int	tailroom = skb_tailroom(skb);
14953ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	__le32	*packet_count;
15053ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	__le32	*packet_len;
15147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
15247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// FIXME:  magic numbers, bleech
15347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
15447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
15547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	if ((!skb_cloned(skb))
15647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			&& ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
15747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
15847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			skb->data = memmove(skb->head + (4 + 4*1),
15947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell					     skb->data, skb->len);
16027a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo			skb_set_tail_pointer(skb, skb->len);
16147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		}
16247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	} else {
16347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		struct sk_buff	*skb2;
16447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
16547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		dev_kfree_skb_any(skb);
16647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		skb = skb2;
16747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		if (!skb)
16847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell			return NULL;
16947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	}
17047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
17147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// attach the packet count to the header
17253ebb3b8264a77b6214f7a405300de8c24a12554Al Viro	packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
17347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	packet_len = packet_count + 1;
17447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
17547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	*packet_count = cpu_to_le32(1);
17647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	*packet_len = cpu_to_le32(length);
17747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
17847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	// add padding byte
17947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	if ((skb->len % dev->maxpacket) == 0)
18047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell		skb_put(skb, 1);
18147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
18247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	return skb;
18347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell}
18447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
18547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
18647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell{
18747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	dev->hard_mtu = GL_RCV_BUF_SIZE;
18847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	dev->net->hard_header_len += 4;
18947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
19047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
19147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	return 0;
19247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell}
19347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
19447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic const struct driver_info	genelink_info = {
19547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.description =	"Genesys GeneLink",
196c261344d3ce3edac781f9d3c7eabe2e96d8e8fe8Arnd Bergmann	.flags =	FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT,
19747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.bind =		genelink_bind,
19847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.rx_fixup =	genelink_rx_fixup,
19947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.tx_fixup =	genelink_tx_fixup,
20047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
20147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.in = 1, .out = 2,
20247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
20347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#ifdef	GENELINK_ACK
20447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.check_connect =genelink_check_connect,
20547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell#endif
20647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell};
20747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
20847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic const struct usb_device_id	products [] = {
20947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
21047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell{
21147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	USB_DEVICE(0x05e3, 0x0502),	// GL620USB-A
21247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.driver_info =	(unsigned long) &genelink_info,
21347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell},
21447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	/* NOT: USB_DEVICE(0x05e3, 0x0501),	// GL620USB
21547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	 * that's half duplex, not currently supported
21647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	 */
21747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	{ },		// END
21847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell};
21947ee3051c856cc2aa95d35d577a8cb37279d540fDavid BrownellMODULE_DEVICE_TABLE(usb, products);
22047ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
22147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownellstatic struct usb_driver gl620a_driver = {
22247ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.name =		"gl620a",
22347ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.id_table =	products,
22447ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.probe =	usbnet_probe,
22547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.disconnect =	usbnet_disconnect,
22647ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.suspend =	usbnet_suspend,
22747ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell	.resume =	usbnet_resume,
22847ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell};
22947ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
230d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(gl620a_driver);
23147ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
23247ee3051c856cc2aa95d35d577a8cb37279d540fDavid BrownellMODULE_AUTHOR("Jiun-Jie Huang");
23347ee3051c856cc2aa95d35d577a8cb37279d540fDavid BrownellMODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
23447ee3051c856cc2aa95d35d577a8cb37279d540fDavid BrownellMODULE_LICENSE("GPL");
23547ee3051c856cc2aa95d35d577a8cb37279d540fDavid Brownell
236