📄 usbnet.c
字号:
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 void nc_flush_complete (struct urb *urb, struct pt_regs *regs){ kfree (urb->context); usb_free_urb(urb);}static void nc_ensure_sync (struct usbnet *dev){ dev->frame_errors++; if (dev->frame_errors > 5) { struct urb *urb; struct usb_ctrlrequest *req; int status; /* Send a flush */ urb = usb_alloc_urb (0, SLAB_ATOMIC); if (!urb) return; req = kmalloc (sizeof *req, GFP_ATOMIC); if (!req) { usb_free_urb (urb); return; } req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; req->bRequest = REQUEST_REGISTER; req->wValue = cpu_to_le16 (USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); req->wIndex = cpu_to_le16 (REG_USBCTL); req->wLength = cpu_to_le16 (0); /* queue an async control request, we don't need * to do anything when it finishes except clean up. */ usb_fill_control_urb (urb, dev->udev, usb_sndctrlpipe (dev->udev, 0), (unsigned char *) req, NULL, 0, nc_flush_complete, req); status = usb_submit_urb (urb, GFP_ATOMIC); if (status) { kfree (req); usb_free_urb (urb); return; } devdbg (dev, "flush net1080; too many framing errors"); dev->frame_errors = 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); nc_ensure_sync (dev); 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); nc_ensure_sync (dev); return 0; } else if (header->hdr_len < MIN_HEADER) { dev->stats.rx_frame_errors++; dbg ("header too short, %d", header->hdr_len); nc_ensure_sync (dev); 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); nc_ensure_sync (dev); // 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); nc_ensure_sync (dev); 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 dev->frame_errors = 0; return 1;}static struct sk_buff *net1080_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags){ int padlen; struct sk_buff *skb2; padlen = ((skb->len + sizeof (struct nc_header) + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; if (!skb_cloned (skb)) { int headroom = skb_headroom (skb); int tailroom = skb_tailroom (skb); if ((padlen + sizeof (struct nc_trailer)) <= tailroom && sizeof (struct nc_header) <= headroom) /* There's enough head and tail room */ return skb; if ((sizeof (struct nc_header) + padlen + sizeof (struct nc_trailer)) < (headroom + tailroom)) { /* There's enough total room, so just readjust */ skb->data = memmove (skb->head + sizeof (struct nc_header), skb->data, skb->len); skb->tail = skb->data + skb->len; return skb; } } /* Create a new skb to use with the correct size */ skb2 = skb_copy_expand (skb, sizeof (struct nc_header), sizeof (struct nc_trailer) + padlen, flags); dev_kfree_skb_any (skb); return skb2;}static const struct driver_info net1080_info = { .description = "NetChip TurboCONNECT", .flags = FLAG_FRAMING_NC, .reset = net1080_reset, .check_connect =net1080_check_connect, .rx_fixup = net1080_rx_fixup, .tx_fixup = net1080_tx_fixup,};#endif /* CONFIG_USB_NET1080 */#ifdef CONFIG_USB_PL2301#define HAVE_HARDWARE/*------------------------------------------------------------------------- * * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com * * The protocol and handshaking used here should be bug-compatible * with the Linux 2.2 "plusb" driver, by Deti Fliegl. * *-------------------------------------------------------------------------*//* * Bits 0-4 can be used for software handshaking; they're set from * one end, cleared from the other, "read" with the interrupt byte. */#define PL_S_EN (1<<7) /* (feature only) suspend enable *//* reserved bit -- rx ready (6) ? */#define PL_TX_READY (1<<5) /* (interrupt only) transmit ready */#define PL_RESET_OUT (1<<4) /* reset output pipe */#define PL_RESET_IN (1<<3) /* reset input pipe */#define PL_TX_C (1<<2) /* transmission complete */#define PL_TX_REQ (1<<1) /* transmission received */#define PL_PEER_E (1<<0) /* peer exists */static inline intpl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index){ return usb_control_msg (dev->udev, usb_rcvctrlpipe (dev->udev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, val, index, NULL, 0, CONTROL_TIMEOUT_JIFFIES);}static inline intpl_clear_QuickLink_features (struct usbnet *dev, int val){ return pl_vendor_req (dev, 1, (u8) val, 0);}static inline intpl_set_QuickLink_features (struct usbnet *dev, int val){ return pl_vendor_req (dev, 3, (u8) val, 0);}/*-------------------------------------------------------------------------*/static int pl_reset (struct usbnet *dev){ /* some units seem to need this reset, others reject it utterly. * FIXME be more like "naplink" or windows drivers. */ (void) pl_set_QuickLink_features (dev, PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E); return 0;}static const struct driver_info prolific_info = { .description = "Prolific PL-2301/PL-2302", .flags = FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset,};#endif /* CONFIG_USB_PL2301 */#ifdef CONFIG_USB_KC2190#define HAVE_HARDWAREstatic const struct driver_info kc2190_info = { .description = "KC Technology KC-190",};#endif /* CONFIG_USB_KC2190 */#ifdef CONFIG_USB_ARMLINUX#define HAVE_HARDWARE/*------------------------------------------------------------------------- * * Intel's SA-1100 chip integrates basic USB support, and is used * in PDAs like some iPaqs, the Yopy, some Zaurus models, and more. * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to * network using minimal USB framing data. * * This describes the driver currently in standard ARM Linux kernels. * The Zaurus uses a different driver (see later). * * PXA25x and PXA210 use XScale cores (ARM v5TE) with better USB support * and different USB endpoint numbering than the SA1100 devices. The * mach-pxa/usb-eth.c driver re-uses the device ids from mach-sa1100 * so we rely on the endpoint descriptors. * *-------------------------------------------------------------------------*/static const struct driver_info linuxdev_info = { .description = "Linux Device", .check_connect = always_connected,};static const struct driver_info yopy_info = { .description = "Yopy", .check_connect = always_connected,};static const struct driver_info blob_info = { .description = "Boot Loader OBject", .check_connect = always_connected,};#endif /* CONFIG_USB_ARMLINUX */#ifdef CONFIG_USB_ZAURUS#define HAVE_HARDWARE#include <linux/crc32.h>/*------------------------------------------------------------------------- * * Zaurus is also a SA-1110 based PDA, but one using a different driver * (and framing) for its USB slave/gadget controller than the case above. * * For the current version of that driver, the main way that framing is * nonstandard (also from perspective of the CDC ethernet model!) is a * crc32, added to help detect when some sa1100 usb-to-memory DMA errata * haven't been fully worked around. * * PXA based models use the same framing, and also can't implement * set_interface properly. * *-------------------------------------------------------------------------*/static struct sk_buff *zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags){ int padlen; struct sk_buff *skb2; padlen = 2; if (!skb_cloned (skb)) { int tailroom = skb_tailroom (skb); if ((padlen + 4) <= tailroom) goto done; } skb2 = skb_copy_expand (skb, 0, 4 + padlen, flags); dev_kfree_skb_any (skb); skb = skb2; if (skb) { u32 fcs;done: fcs = crc32_le (~0, skb->data, skb->len); fcs = ~fcs; *skb_put (skb, 1) = fcs & 0xff; *skb_put (skb, 1) = (fcs>> 8) & 0xff; *skb_put (skb, 1) = (fcs>>16) & 0xff; *skb_put (skb, 1) = (fcs>>24) & 0xff; } return skb;}static const struct driver_info zaurus_sl5x00_info = { .description = "Sharp Zaurus SL-5x00", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, .bind = generic_cdc_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup,};#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info)static const struct driver_info zaurus_pxa_info = { .description = "Sharp Zaurus, PXA-2xx based", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, .bind = generic_cdc_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup,};#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info)static const struct driver_info olympus_mxl_info = { .description = "Olympus R1000", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, .bind = generic_cdc_bind, .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup,};#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info)#else/* blacklist all those devices */#define ZAURUS_STRONGARM_INFO 0#define ZAURUS_PXA_INFO 0#define OLYMPUS_MXL_INFO 0#endif/*------------------------------------------------------------------------- * * Network Device Driver (peer link to "Host Device", from USB host) * *-------------------------------------------------------------------------*/static int usbnet_change_mtu (struct net_device *net, int new_mtu){ struct usbnet *dev = netdev_priv(net); if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET) return -EINVAL;#ifdef CONFIG_USB_NET1080 if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) { if (FRAMED_SIZE (new_mtu) > MAX_PACKET) return -EINVAL; }#endif#ifdef CONFIG_USB_GENESYS if (((dev->driver_info->flags) & FLAG_FRAMING_GL) && new_mtu > GL_MAX_PACKET_LEN) return -EINVAL;#endif // no second zero-length packet read wanted after mtu-sized packets if (((new_mtu + sizeof (struct ethhdr)) % dev->maxpacket) == 0) return -EDOM; net->mtu = new_mtu; return 0;}/*-------------------------------------------------------------------------*/static struct net_device_stats *usbnet_get_stats (struct net_device *net){ struct usbnet *dev = netdev_priv(net); return &dev->stats;}/*-------------------------------------------------------------------------*//* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from * completion callbacks. 2.5 should have fixed those bugs... */static void defer_bh (struct usbnet *dev, struct sk_buff *skb){ struct sk_buff_head *list = skb->list; unsigned long flags; spin_lock_irqsave (&list->lock, flags); __skb_unlink (skb, list); spin_unlock (&list->lock); spin_lock (&dev->done.lock); __skb_queue_tail (&dev->done, skb); if (dev->done.qlen == 1) tasklet_schedule (&dev->bh); spin_unlock_irqrestore (&dev->done.lock, flags);}/* some work can't be done in tasklets, so we use keventd * * NOTE: annoying asymmetry: if it's active, schedule_work() fails, * but tasklet_schedule() doesn't. hope the failure is rare. */static void defer_kevent (struct usbnet *dev, int work){ set_bit (work, &dev->flags); if (!schedule_work (&dev->kevent)) deverr (dev, "kevent %d may have been dropped", work); else devdbg (dev, "kevent %d scheduled", work);}/*-------------------------------------------------------------------------*/static void rx_complete (struct
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -