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