📄 usbnet.c
字号:
header = (struct gl_header *) skb->data; // get the packet count of the received skb le32_to_cpus (&header->packet_count); if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS) || (header->packet_count < 0)) { dbg ("genelink: illegal received packet count %d", header->packet_count); return 0; } // set the current packet pointer to the first packet packet = &header->packets; // decrement the length for the packet count size 4 bytes skb_pull (skb, 4); while (header->packet_count > 1) { // get the packet length size = packet->packet_length; // this may be a broken packet if (size > GL_MAX_PACKET_LEN) { dbg ("genelink: illegal rx length %d", size); return 0; } // allocate the skb for the individual packet gl_skb = alloc_skb (size, GFP_ATOMIC); if (gl_skb) { // copy the packet data to the new skb memcpy (gl_skb->data, packet->packet_data, size); // set skb data size gl_skb->len = size; gl_skb->dev = &dev->net; // determine the packet's protocol ID gl_skb->protocol = eth_type_trans (gl_skb, &dev->net); // update the status dev->stats.rx_packets++; dev->stats.rx_bytes += size; // notify os of the received packet status = netif_rx (gl_skb); } // advance to the next packet packet = (struct gl_packet *) &packet->packet_data [size]; header->packet_count--; // shift the data pointer to the next gl_packet skb_pull (skb, size + 4); } // skip the packet length field 4 bytes skb_pull (skb, 4); if (skb->len > GL_MAX_PACKET_LEN) { dbg ("genelink: illegal rx length %d", skb->len); return 0; } return 1;}static struct sk_buff *genelink_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags){ int padlen; int length = skb->len; int headroom = skb_headroom (skb); int tailroom = skb_tailroom (skb); u32 *packet_count; u32 *packet_len; // FIXME: magic numbers, bleech padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1; if ((!skb_cloned (skb)) && ((headroom + tailroom) >= (padlen + (4 + 4*1)))) { if ((headroom < (4 + 4*1)) || (tailroom < padlen)) { skb->data = memmove (skb->head + (4 + 4*1), skb->data, skb->len); skb->tail = skb->data + skb->len; } } else { struct sk_buff *skb2; skb2 = skb_copy_expand (skb, (4 + 4*1) , padlen, flags); dev_kfree_skb_any (skb); skb = skb2; } // attach the packet count to the header packet_count = (u32 *) skb_push (skb, (4 + 4*1)); packet_len = packet_count + 1; // FIXME little endian? *packet_count = 1; *packet_len = length; // add padding byte if ((skb->len % EP_SIZE (dev)) == 0) skb_put (skb, 1); return skb;}static const struct driver_info genelink_info = { .description = "Genesys GeneLink", .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, .rx_fixup = genelink_rx_fixup, .tx_fixup = genelink_tx_fixup, .in = 1, .out = 2, .epsize =64,#ifdef GENELINK_ACK .check_connect =genelink_check_connect,#endif};#endif /* CONFIG_USB_GENESYS */#ifdef CONFIG_USB_LINUXDEV/*------------------------------------------------------------------------- * * This could talk to a device that uses Linux, such as a PDA or * an embedded system, or in fact to any "smart" device using this * particular mapping of USB and Ethernet. * * Such a Linux host would need a "USB Device Controller" hardware * (not "USB Host Controller"), and a network driver talking to that * hardware. * * One example is Intel's SA-1100 chip, which integrates basic USB * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA. * And others too, like the Yopy. * *-------------------------------------------------------------------------*/static const struct driver_info linuxdev_info = { .description = "Linux Device", .in = 2, .out = 1, .epsize = 64,};#endif /* CONFIG_USB_LINUXDEV */#ifdef CONFIG_USB_NET1080/*------------------------------------------------------------------------- * * Netchip 1080 driver ... http://www.netchip.com * Used in LapLink cables * *-------------------------------------------------------------------------*//* * NetChip framing of ethernet packets, supporting additional error * checks for links that may drop bulk packets from inside messages. * Odd USB length == always short read for last usb packet. * - nc_header * - Ethernet header (14 bytes) * - payload * - (optional padding byte, if needed so length becomes odd) * - nc_trailer * * This framing is to be avoided for non-NetChip devices. */struct nc_header { // packed: u16 hdr_len; // sizeof nc_header (LE, all) u16 packet_len; // payload size (including ethhdr) u16 packet_id; // detects dropped packets#define MIN_HEADER 6 // all else is optional, and must start with: // u16 vendorId; // from usb-if // u16 productId;} __attribute__((__packed__));#define PAD_BYTE ((unsigned char)0xAC)struct nc_trailer { u16 packet_id;} __attribute__((__packed__));// packets may use FLAG_FRAMING_NC and optional pad#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \ + sizeof (struct ethhdr) \ + (mtu) \ + 1 \ + sizeof (struct nc_trailer))#define MIN_FRAMED FRAMED_SIZE(0)/* * Zero means no timeout; else, how long a 64 byte bulk packet may be queued * before the hardware drops it. If that's done, the driver will need to * frame network packets to guard against the dropped USB packets. The win32 * driver sets this for both sides of the link. */#define NC_READ_TTL_MS ((u8)255) // ms/* * We ignore most registers and EEPROM contents. */#define REG_USBCTL ((u8)0x04)#define REG_TTL ((u8)0x10)#define REG_STATUS ((u8)0x11)/* * Vendor specific requests to read/write data */#define REQUEST_REGISTER ((u8)0x10)#define REQUEST_EEPROM ((u8)0x11)static intnc_vendor_read (struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr){ int status = usb_control_msg (dev->udev, usb_rcvctrlpipe (dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, regnum, retval_ptr, sizeof *retval_ptr, CONTROL_TIMEOUT_JIFFIES); if (status > 0) status = 0; if (!status) le16_to_cpus (retval_ptr); return status;}static inline intnc_register_read (struct usbnet *dev, u8 regnum, u16 *retval_ptr){ return nc_vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr);}// no retval ... can become async, usable in_interrupt()static voidnc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value){ usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, regnum, 0, 0, // data is in setup packet CONTROL_TIMEOUT_JIFFIES);}static inline voidnc_register_write (struct usbnet *dev, u8 regnum, u16 value){ nc_vendor_write (dev, REQUEST_REGISTER, regnum, value);}#if 0static void nc_dump_registers (struct usbnet *dev){ u8 reg; u16 *vp = kmalloc (sizeof (u16)); if (!vp) { dbg ("no memory?"); return; } dbg ("%s registers:", dev->net.name); for (reg = 0; reg < 0x20; reg++) { int retval; // reading some registers is trouble if (reg >= 0x08 && reg <= 0xf) continue; if (reg >= 0x12 && reg <= 0x1e) continue; retval = nc_register_read (dev, reg, vp); if (retval < 0) dbg ("%s reg [0x%x] ==> error %d", dev->net.name, reg, retval); else dbg ("%s reg [0x%x] = 0x%x", dev->net.name, reg, *vp); } kfree (vp);}#endif/*-------------------------------------------------------------------------*//* * Control register */#define USBCTL_WRITABLE_MASK 0x1f0f// bits 15-13 reserved, r/o#define USBCTL_ENABLE_LANG (1 << 12)#define USBCTL_ENABLE_MFGR (1 << 11)#define USBCTL_ENABLE_PROD (1 << 10)#define USBCTL_ENABLE_SERIAL (1 << 9)#define USBCTL_ENABLE_DEFAULTS (1 << 8)// bits 7-4 reserved, r/o#define USBCTL_FLUSH_OTHER (1 << 3)#define USBCTL_FLUSH_THIS (1 << 2)#define USBCTL_DISCONN_OTHER (1 << 1)#define USBCTL_DISCONN_THIS (1 << 0)static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl){#ifdef DEBUG devdbg (dev, "net1080 %s-%s usbctl 0x%x:%s%s%s%s%s;" " this%s%s;" " other%s%s; r/o 0x%x", dev->udev->bus->bus_name, dev->udev->devpath, usbctl, (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", usbctl & ~USBCTL_WRITABLE_MASK );#endif}/*-------------------------------------------------------------------------*//* * Status register */#define STATUS_PORT_A (1 << 15)#define STATUS_CONN_OTHER (1 << 14)#define STATUS_SUSPEND_OTHER (1 << 13)#define STATUS_MAILBOX_OTHER (1 << 12)#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03)#define STATUS_CONN_THIS (1 << 6)#define STATUS_SUSPEND_THIS (1 << 5)#define STATUS_MAILBOX_THIS (1 << 4)#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03)#define STATUS_UNSPEC_MASK 0x0c8c#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK))static inline void nc_dump_status (struct usbnet *dev, u16 status){#ifdef DEBUG devdbg (dev, "net1080 %s-%s status 0x%x:" " this (%c) PKT=%d%s%s%s;" " other PKT=%d%s%s%s; unspec 0x%x", dev->udev->bus->bus_name, dev->udev->devpath, status, // XXX the packet counts don't seem right // (1 at reset, not 0); maybe UNSPEC too (status & STATUS_PORT_A) ? 'A' : 'B', STATUS_PACKETS_THIS (status), (status & STATUS_CONN_THIS) ? " CON" : "", (status & STATUS_SUSPEND_THIS) ? " SUS" : "", (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", STATUS_PACKETS_OTHER (status), (status & STATUS_CONN_OTHER) ? " CON" : "", (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", status & STATUS_UNSPEC_MASK );#endif}/*-------------------------------------------------------------------------*//* * TTL register */#define TTL_THIS(ttl) (0x00ff & ttl)#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8))#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this))))static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl){#ifdef DEBUG devdbg (dev, "net1080 %s-%s ttl 0x%x this = %d, other = %d", dev->udev->bus->bus_name, dev->udev->devpath, ttl, TTL_THIS (ttl), TTL_OTHER (ttl) );#endif}/*-------------------------------------------------------------------------*/static int net1080_reset (struct usbnet *dev){ u16 usbctl, status, ttl; u16 *vp = kmalloc (sizeof (u16), GFP_KERNEL); int retval; if (!vp) return -ENOMEM; // nc_dump_registers (dev); if ((retval = nc_register_read (dev, REG_STATUS, vp)) < 0) { dbg ("can't read %s-%s status: %d", dev->udev->bus->bus_name, dev->udev->devpath, retval); goto done; } status = *vp; // nc_dump_status (dev, status); if ((retval = nc_register_read (dev, REG_USBCTL, vp)) < 0) { dbg ("can't read USBCTL, %d", retval); goto done; } usbctl = *vp; // nc_dump_usbctl (dev, usbctl); nc_register_write (dev, REG_USBCTL, USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); if ((retval = nc_register_read (dev, REG_TTL, vp)) < 0) { dbg ("can't read TTL, %d", retval); goto done; } ttl = *vp; // nc_dump_ttl (dev, ttl); nc_register_write (dev, REG_TTL, MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) ); dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS); if (dev->msg_level >= 2) devinfo (dev, "port %c, peer %sconnected", (status & STATUS_PORT_A) ? 'A' : 'B', (status & STATUS_CONN_OTHER) ? "" : "dis" ); retval = 0;done: kfree (vp); return retval;}static int net1080_check_connect (struct usbnet *dev){ int retval; u16 status; u16 *vp = kmalloc (sizeof (u16), GFP_KERNEL); if (!vp) return -ENOMEM; retval = nc_register_read (dev, REG_STATUS, vp); status = *vp; kfree (vp); if (retval != 0) { dbg ("%s net1080_check_conn read - %d", dev->net.name, retval); return retval; } if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) return -ENOLINK; return 0;}static int net1080_rx_fixup (struct usbnet *dev, struct sk_buff *skb){ struct nc_header *header; struct nc_trailer *trailer; if (!(skb->len & 0x01) || MIN_FRAMED > skb->len || skb->len > FRAMED_SIZE (dev->net.mtu)) { dev->stats.rx_frame_errors++; dbg ("rx framesize %d range %d..%d mtu %d", skb->len, (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu), dev->net.mtu); return 0; } header = (struct nc_header *) skb->data; le16_to_cpus (&header->hdr_len); le16_to_cpus (&header->packet_len); if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) { dev->stats.rx_frame_errors++; dbg ("packet too big, %d", header->packet_len); return 0; } else if (header->hdr_len < MIN_HEADER) { dev->stats.rx_frame_errors++; dbg ("header too short, %d", header->hdr_len); return 0; } else if (header->hdr_len > MIN_HEADER) { // out of band data for us? dbg ("header OOB, %d bytes", header->hdr_len - MIN_HEADER); // switch (vendor/product ids) { ... } } skb_pull (skb, header->hdr_len); trailer = (struct nc_trailer *) (skb->data + skb->len - sizeof *trailer); skb_trim (skb, skb->len - sizeof *trailer); if ((header->packet_len & 0x01) == 0) { if (skb->data [header->packet_len] != PAD_BYTE) { dev->stats.rx_frame_errors++; dbg ("bad pad"); return 0; } skb_trim (skb, skb->len - 1); } if (skb->len != header->packet_len) { dev->stats.rx_frame_errors++; dbg ("bad packet len %d (expected %d)", skb->len, header->packet_len); return 0; } if (header->packet_id != get_unaligned (&trailer->packet_id)) { dev->stats.rx_fifo_errors++; dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", header->packet_id, trailer->packet_id); return 0; }#if 0 devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len, header->packet_len, header->packet_id);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -