linux/drivers/net/usb/gl620a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * GeneSys GL620USB-A based links
   4 * Copyright (C) 2001 by Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
   5 * Copyright (C) 2001 by Stanislav Brabec <utx@penguin.cz>
   6 */
   7
   8// #define      DEBUG                   // error path messages, extra info
   9// #define      VERBOSE                 // more; success messages
  10
  11#include <linux/module.h>
  12#include <linux/netdevice.h>
  13#include <linux/etherdevice.h>
  14#include <linux/ethtool.h>
  15#include <linux/workqueue.h>
  16#include <linux/mii.h>
  17#include <linux/usb.h>
  18#include <linux/usb/usbnet.h>
  19#include <linux/gfp.h>
  20
  21
  22/*
  23 * GeneSys GL620USB-A (www.genesyslogic.com.tw)
  24 *
  25 * ... should partially interop with the Win32 driver for this hardware.
  26 * The GeneSys docs imply there's some NDIS issue motivating this framing.
  27 *
  28 * Some info from GeneSys:
  29 *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
  30 *    (Some cables, like the BAFO-100c, use the half duplex version.)
  31 *  - For the full duplex model, the low bit of the version code says
  32 *    which side is which ("left/right").
  33 *  - For the half duplex type, a control/interrupt handshake settles
  34 *    the transfer direction.  (That's disabled here, partially coded.)
  35 *    A control URB would block until other side writes an interrupt.
  36 *
  37 * Original code from Jiun-Jie Huang <huangjj@genesyslogic.com.tw>
  38 * and merged into "usbnet" by Stanislav Brabec <utx@penguin.cz>.
  39 */
  40
  41// control msg write command
  42#define GENELINK_CONNECT_WRITE                  0xF0
  43// interrupt pipe index
  44#define GENELINK_INTERRUPT_PIPE                 0x03
  45// interrupt read buffer size
  46#define INTERRUPT_BUFSIZE                       0x08
  47// interrupt pipe interval value
  48#define GENELINK_INTERRUPT_INTERVAL             0x10
  49// max transmit packet number per transmit
  50#define GL_MAX_TRANSMIT_PACKETS                 32
  51// max packet length
  52#define GL_MAX_PACKET_LEN                       1514
  53// max receive buffer size
  54#define GL_RCV_BUF_SIZE         \
  55        (((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
  56
  57struct gl_packet {
  58        __le32          packet_length;
  59        char            packet_data [1];
  60};
  61
  62struct gl_header {
  63        __le32                  packet_count;
  64        struct gl_packet        packets;
  65};
  66
  67static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  68{
  69        struct gl_header        *header;
  70        struct gl_packet        *packet;
  71        struct sk_buff          *gl_skb;
  72        u32                     size;
  73        u32                     count;
  74
  75        /* This check is no longer done by usbnet */
  76        if (skb->len < dev->net->hard_header_len)
  77                return 0;
  78
  79        header = (struct gl_header *) skb->data;
  80
  81        // get the packet count of the received skb
  82        count = le32_to_cpu(header->packet_count);
  83        if (count > GL_MAX_TRANSMIT_PACKETS) {
  84                netdev_dbg(dev->net,
  85                           "genelink: invalid received packet count %u\n",
  86                           count);
  87                return 0;
  88        }
  89
  90        // set the current packet pointer to the first packet
  91        packet = &header->packets;
  92
  93        // decrement the length for the packet count size 4 bytes
  94        skb_pull(skb, 4);
  95
  96        while (count > 1) {
  97                // get the packet length
  98                size = le32_to_cpu(packet->packet_length);
  99
 100                // this may be a broken packet
 101                if (size > GL_MAX_PACKET_LEN) {
 102                        netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
 103                                   size);
 104                        return 0;
 105                }
 106
 107                // allocate the skb for the individual packet
 108                gl_skb = alloc_skb(size, GFP_ATOMIC);
 109                if (gl_skb) {
 110
 111                        // copy the packet data to the new skb
 112                        skb_put_data(gl_skb, packet->packet_data, size);
 113                        usbnet_skb_return(dev, gl_skb);
 114                }
 115
 116                // advance to the next packet
 117                packet = (struct gl_packet *)&packet->packet_data[size];
 118                count--;
 119
 120                // shift the data pointer to the next gl_packet
 121                skb_pull(skb, size + 4);
 122        }
 123
 124        // skip the packet length field 4 bytes
 125        skb_pull(skb, 4);
 126
 127        if (skb->len > GL_MAX_PACKET_LEN) {
 128                netdev_dbg(dev->net, "genelink: invalid rx length %d\n",
 129                           skb->len);
 130                return 0;
 131        }
 132        return 1;
 133}
 134
 135static struct sk_buff *
 136genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
 137{
 138        int     padlen;
 139        int     length = skb->len;
 140        int     headroom = skb_headroom(skb);
 141        int     tailroom = skb_tailroom(skb);
 142        __le32  *packet_count;
 143        __le32  *packet_len;
 144
 145        // FIXME:  magic numbers, bleech
 146        padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
 147
 148        if ((!skb_cloned(skb))
 149                        && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) {
 150                if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
 151                        skb->data = memmove(skb->head + (4 + 4*1),
 152                                             skb->data, skb->len);
 153                        skb_set_tail_pointer(skb, skb->len);
 154                }
 155        } else {
 156                struct sk_buff  *skb2;
 157                skb2 = skb_copy_expand(skb, (4 + 4*1) , padlen, flags);
 158                dev_kfree_skb_any(skb);
 159                skb = skb2;
 160                if (!skb)
 161                        return NULL;
 162        }
 163
 164        // attach the packet count to the header
 165        packet_count = skb_push(skb, (4 + 4 * 1));
 166        packet_len = packet_count + 1;
 167
 168        *packet_count = cpu_to_le32(1);
 169        *packet_len = cpu_to_le32(length);
 170
 171        // add padding byte
 172        if ((skb->len % dev->maxpacket) == 0)
 173                skb_put(skb, 1);
 174
 175        return skb;
 176}
 177
 178static int genelink_bind(struct usbnet *dev, struct usb_interface *intf)
 179{
 180        dev->hard_mtu = GL_RCV_BUF_SIZE;
 181        dev->net->hard_header_len += 4;
 182        dev->in = usb_rcvbulkpipe(dev->udev, dev->driver_info->in);
 183        dev->out = usb_sndbulkpipe(dev->udev, dev->driver_info->out);
 184        return 0;
 185}
 186
 187static const struct driver_info genelink_info = {
 188        .description =  "Genesys GeneLink",
 189        .flags =        FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT,
 190        .bind =         genelink_bind,
 191        .rx_fixup =     genelink_rx_fixup,
 192        .tx_fixup =     genelink_tx_fixup,
 193
 194        .in = 1, .out = 2,
 195
 196#ifdef  GENELINK_ACK
 197        .check_connect =genelink_check_connect,
 198#endif
 199};
 200
 201static const struct usb_device_id       products [] = {
 202
 203{
 204        USB_DEVICE(0x05e3, 0x0502),     // GL620USB-A
 205        .driver_info =  (unsigned long) &genelink_info,
 206},
 207        /* NOT: USB_DEVICE(0x05e3, 0x0501),     // GL620USB
 208         * that's half duplex, not currently supported
 209         */
 210        { },            // END
 211};
 212MODULE_DEVICE_TABLE(usb, products);
 213
 214static struct usb_driver gl620a_driver = {
 215        .name =         "gl620a",
 216        .id_table =     products,
 217        .probe =        usbnet_probe,
 218        .disconnect =   usbnet_disconnect,
 219        .suspend =      usbnet_suspend,
 220        .resume =       usbnet_resume,
 221        .disable_hub_initiated_lpm = 1,
 222};
 223
 224module_usb_driver(gl620a_driver);
 225
 226MODULE_AUTHOR("Jiun-Jie Huang");
 227MODULE_DESCRIPTION("GL620-USB-A Host-to-Host Link cables");
 228MODULE_LICENSE("GPL");
 229
 230