11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25b2fc499SJeff Garzik /*
35b2fc499SJeff Garzik * GeneSys GL620USB-A based links
45b2fc499SJeff Garzik * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
55b2fc499SJeff Garzik * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
65b2fc499SJeff Garzik */
75b2fc499SJeff Garzik
85b2fc499SJeff Garzik // #define DEBUG // error path messages, extra info
95b2fc499SJeff Garzik // #define VERBOSE // more; success messages
105b2fc499SJeff Garzik
115b2fc499SJeff Garzik #include <linux/module.h>
125b2fc499SJeff Garzik #include <linux/netdevice.h>
135b2fc499SJeff Garzik #include <linux/etherdevice.h>
145b2fc499SJeff Garzik #include <linux/ethtool.h>
155b2fc499SJeff Garzik #include <linux/workqueue.h>
165b2fc499SJeff Garzik #include <linux/mii.h>
175b2fc499SJeff Garzik #include <linux/usb.h>
183692e94fSJussi Kivilinna #include <linux/usb/usbnet.h>
195a0e3ad6STejun Heo #include <linux/gfp.h>
205b2fc499SJeff Garzik
215b2fc499SJeff Garzik
225b2fc499SJeff Garzik /*
235b2fc499SJeff Garzik * GeneSys GL620USB-A (www.genesyslogic.com.tw)
245b2fc499SJeff Garzik *
255b2fc499SJeff Garzik * ... should partially interop with the Win32 driver for this hardware.
265b2fc499SJeff Garzik * The GeneSys docs imply there's some NDIS issue motivating this framing.
275b2fc499SJeff Garzik *
285b2fc499SJeff Garzik * Some info from GeneSys:
295b2fc499SJeff Garzik * - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
305b2fc499SJeff Garzik * (Some cables, like the BAFO-100c, use the half duplex version.)
315b2fc499SJeff Garzik * - For the full duplex model, the low bit of the version code says
325b2fc499SJeff Garzik * which side is which ("left/right").
335b2fc499SJeff Garzik * - For the half duplex type, a control/interrupt handshake settles
345b2fc499SJeff Garzik * the transfer direction. (That's disabled here, partially coded.)
355b2fc499SJeff Garzik * A control URB would block until other side writes an interrupt.
365b2fc499SJeff Garzik *
375b2fc499SJeff Garzik * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
385b2fc499SJeff Garzik * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
395b2fc499SJeff Garzik */
405b2fc499SJeff Garzik
415b2fc499SJeff Garzik // control msg write command
425b2fc499SJeff Garzik #define GENELINK_CONNECT_WRITE 0xF0
435b2fc499SJeff Garzik // interrupt pipe index
445b2fc499SJeff Garzik #define GENELINK_INTERRUPT_PIPE 0x03
455b2fc499SJeff Garzik // interrupt read buffer size
465b2fc499SJeff Garzik #define INTERRUPT_BUFSIZE 0x08
475b2fc499SJeff Garzik // interrupt pipe interval value
485b2fc499SJeff Garzik #define GENELINK_INTERRUPT_INTERVAL 0x10
495b2fc499SJeff Garzik // max transmit packet number per transmit
505b2fc499SJeff Garzik #define GL_MAX_TRANSMIT_PACKETS 32
515b2fc499SJeff Garzik // max packet length
525b2fc499SJeff Garzik #define GL_MAX_PACKET_LEN 1514
535b2fc499SJeff Garzik // max receive buffer size
545b2fc499SJeff Garzik #define GL_RCV_BUF_SIZE \
555b2fc499SJeff Garzik (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
565b2fc499SJeff Garzik
575b2fc499SJeff Garzik struct gl_packet {
585b2fc499SJeff Garzik __le32 packet_length;
59cc727b64SGustavo A. R. Silva char packet_data[];
605b2fc499SJeff Garzik };
615b2fc499SJeff Garzik
625b2fc499SJeff Garzik struct gl_header {
635b2fc499SJeff Garzik __le32 packet_count;
645b2fc499SJeff Garzik struct gl_packet packets;
655b2fc499SJeff Garzik };
665b2fc499SJeff Garzik
genelink_rx_fixup(struct usbnet * dev,struct sk_buff * skb)675b2fc499SJeff Garzik static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
685b2fc499SJeff Garzik {
695b2fc499SJeff Garzik struct gl_header *header;
705b2fc499SJeff Garzik struct gl_packet *packet;
715b2fc499SJeff Garzik struct sk_buff *gl_skb;
725b2fc499SJeff Garzik u32 size;
735b2fc499SJeff Garzik u32 count;
745b2fc499SJeff Garzik
75eb85569fSEmil Goode /* This check is no longer done by usbnet */
76eb85569fSEmil Goode if (skb->len < dev->net->hard_header_len)
77eb85569fSEmil Goode return 0;
78eb85569fSEmil Goode
795b2fc499SJeff Garzik header = (struct gl_header *) skb->data;
805b2fc499SJeff Garzik
815b2fc499SJeff Garzik // get the packet count of the received skb
825b2fc499SJeff Garzik count = le32_to_cpu(header->packet_count);
835b2fc499SJeff Garzik if (count > GL_MAX_TRANSMIT_PACKETS) {
8449ae25b0SGreg Kroah-Hartman netdev_dbg(dev->net,
8549ae25b0SGreg Kroah-Hartman "genelink: invalid received packet count %u\n",
8649ae25b0SGreg Kroah-Hartman count);
875b2fc499SJeff Garzik return 0;
885b2fc499SJeff Garzik }
895b2fc499SJeff Garzik
905b2fc499SJeff Garzik // set the current packet pointer to the first packet
915b2fc499SJeff Garzik packet = &header->packets;
925b2fc499SJeff Garzik
935b2fc499SJeff Garzik // decrement the length for the packet count size 4 bytes
945b2fc499SJeff Garzik skb_pull(skb, 4);
955b2fc499SJeff Garzik
965b2fc499SJeff Garzik while (count > 1) {
975b2fc499SJeff Garzik // get the packet length
985b2fc499SJeff Garzik size = le32_to_cpu(packet->packet_length);
995b2fc499SJeff Garzik
1005b2fc499SJeff Garzik // this may be a broken packet
1015b2fc499SJeff Garzik if (size > GL_MAX_PACKET_LEN) {
10249ae25b0SGreg Kroah-Hartman netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
10349ae25b0SGreg Kroah-Hartman size);
1045b2fc499SJeff Garzik return 0;
1055b2fc499SJeff Garzik }
1065b2fc499SJeff Garzik
1075b2fc499SJeff Garzik // allocate the skb for the individual packet
1085b2fc499SJeff Garzik gl_skb = alloc_skb(size, GFP_ATOMIC);
1095b2fc499SJeff Garzik if (gl_skb) {
1105b2fc499SJeff Garzik
1115b2fc499SJeff Garzik // copy the packet data to the new skb
11259ae1d12SJohannes Berg skb_put_data(gl_skb, packet->packet_data, size);
1135b2fc499SJeff Garzik usbnet_skb_return(dev, gl_skb);
1145b2fc499SJeff Garzik }
1155b2fc499SJeff Garzik
1165b2fc499SJeff Garzik // advance to the next packet
1175b2fc499SJeff Garzik packet = (struct gl_packet *)&packet->packet_data[size];
1185b2fc499SJeff Garzik count--;
1195b2fc499SJeff Garzik
1205b2fc499SJeff Garzik // shift the data pointer to the next gl_packet
1215b2fc499SJeff Garzik skb_pull(skb, size + 4);
1225b2fc499SJeff Garzik }
1235b2fc499SJeff Garzik
1245b2fc499SJeff Garzik // skip the packet length field 4 bytes
1255b2fc499SJeff Garzik skb_pull(skb, 4);
1265b2fc499SJeff Garzik
1275b2fc499SJeff Garzik if (skb->len > GL_MAX_PACKET_LEN) {
12849ae25b0SGreg Kroah-Hartman netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
12949ae25b0SGreg Kroah-Hartman skb->len);
1305b2fc499SJeff Garzik return 0;
1315b2fc499SJeff Garzik }
1325b2fc499SJeff Garzik return 1;
1335b2fc499SJeff Garzik }
1345b2fc499SJeff Garzik
1355b2fc499SJeff Garzik static struct sk_buff *
genelink_tx_fixup(struct usbnet * dev,struct sk_buff * skb,gfp_t flags)1365b2fc499SJeff Garzik genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
1375b2fc499SJeff Garzik {
1385b2fc499SJeff Garzik int padlen;
1395b2fc499SJeff Garzik int length = skb->len;
1405b2fc499SJeff Garzik int headroom = skb_headroom(skb);
1415b2fc499SJeff Garzik int tailroom = skb_tailroom(skb);
1425b2fc499SJeff Garzik __le32 *packet_count;
1435b2fc499SJeff Garzik __le32 *packet_len;
1445b2fc499SJeff Garzik
1455b2fc499SJeff Garzik // FIXME: magic numbers, bleech
1465b2fc499SJeff Garzik padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
1475b2fc499SJeff Garzik
1485b2fc499SJeff Garzik if ((!skb_cloned(skb))
1495b2fc499SJeff Garzik && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
1505b2fc499SJeff Garzik if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
1515b2fc499SJeff Garzik skb->data = memmove(skb->head + (4 + 4*1),
1525b2fc499SJeff Garzik skb->data, skb->len);
1535b2fc499SJeff Garzik skb_set_tail_pointer(skb, skb->len);
1545b2fc499SJeff Garzik }
1555b2fc499SJeff Garzik } else {
1565b2fc499SJeff Garzik struct sk_buff *skb2;
1575b2fc499SJeff Garzik skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
1585b2fc499SJeff Garzik dev_kfree_skb_any(skb);
1595b2fc499SJeff Garzik skb = skb2;
1605b2fc499SJeff Garzik if (!skb)
1615b2fc499SJeff Garzik return NULL;
1625b2fc499SJeff Garzik }
1635b2fc499SJeff Garzik
1645b2fc499SJeff Garzik // attach the packet count to the header
165d58ff351SJohannes Berg packet_count = skb_push(skb, (4 + 4 * 1));
1665b2fc499SJeff Garzik packet_len = packet_count + 1;
1675b2fc499SJeff Garzik
1685b2fc499SJeff Garzik *packet_count = cpu_to_le32(1);
1695b2fc499SJeff Garzik *packet_len = cpu_to_le32(length);
1705b2fc499SJeff Garzik
1715b2fc499SJeff Garzik // add padding byte
1725b2fc499SJeff Garzik if ((skb->len % dev->maxpacket) == 0)
1735b2fc499SJeff Garzik skb_put(skb, 1);
1745b2fc499SJeff Garzik
1755b2fc499SJeff Garzik return skb;
1765b2fc499SJeff Garzik }
1775b2fc499SJeff Garzik
genelink_bind(struct usbnet * dev,struct usb_interface * intf)1785b2fc499SJeff Garzik static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
1795b2fc499SJeff Garzik {
1805b2fc499SJeff Garzik dev->hard_mtu = GL_RCV_BUF_SIZE;
1815b2fc499SJeff Garzik dev->net->hard_header_len += 4;
182*a2ee5e55SNikita Zhandarovich return usbnet_get_endpoints(dev, intf);
1835b2fc499SJeff Garzik }
1845b2fc499SJeff Garzik
1855b2fc499SJeff Garzik static const struct driver_info genelink_info = {
1865b2fc499SJeff Garzik .description = "Genesys GeneLink",
187c261344dSArnd Bergmann .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT,
1885b2fc499SJeff Garzik .bind = genelink_bind,
1895b2fc499SJeff Garzik .rx_fixup = genelink_rx_fixup,
1905b2fc499SJeff Garzik .tx_fixup = genelink_tx_fixup,
1915b2fc499SJeff Garzik
1925b2fc499SJeff Garzik .in = 1, .out = 2,
1935b2fc499SJeff Garzik
1945b2fc499SJeff Garzik #ifdef GENELINK_ACK
1955b2fc499SJeff Garzik .check_connect =genelink_check_connect,
1965b2fc499SJeff Garzik #endif
1975b2fc499SJeff Garzik };
1985b2fc499SJeff Garzik
1995b2fc499SJeff Garzik static const struct usb_device_id products [] = {
2005b2fc499SJeff Garzik
2015b2fc499SJeff Garzik {
2025b2fc499SJeff Garzik USB_DEVICE(0x05e3, 0x0502), // GL620USB-A
2035b2fc499SJeff Garzik .driver_info = (unsigned long) &genelink_info,
2045b2fc499SJeff Garzik },
2055b2fc499SJeff Garzik /* NOT: USB_DEVICE(0x05e3, 0x0501), // GL620USB
2065b2fc499SJeff Garzik * that's half duplex, not currently supported
2075b2fc499SJeff Garzik */
2085b2fc499SJeff Garzik { }, // END
2095b2fc499SJeff Garzik };
2105b2fc499SJeff Garzik MODULE_DEVICE_TABLE(usb, products);
2115b2fc499SJeff Garzik
2125b2fc499SJeff Garzik static struct usb_driver gl620a_driver = {
2135b2fc499SJeff Garzik .name = "gl620a",
2145b2fc499SJeff Garzik .id_table = products,
2155b2fc499SJeff Garzik .probe = usbnet_probe,
2165b2fc499SJeff Garzik .disconnect = usbnet_disconnect,
2175b2fc499SJeff Garzik .suspend = usbnet_suspend,
2185b2fc499SJeff Garzik .resume = usbnet_resume,
219e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1,
2205b2fc499SJeff Garzik };
2215b2fc499SJeff Garzik
222d632eb1bSGreg Kroah-Hartman module_usb_driver(gl620a_driver);
2235b2fc499SJeff Garzik
2245b2fc499SJeff Garzik MODULE_AUTHOR("Jiun-Jie Huang");
2255b2fc499SJeff Garzik MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
2265b2fc499SJeff Garzik MODULE_LICENSE("GPL");
2275b2fc499SJeff Garzik
228