usbnet.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,377 行 · 第 1/5 页
C
2,377 行
size, CONTROL_TIMEOUT_JIFFIES);}static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data){ return usb_control_msg( dev->udev, usb_sndctrlpipe(dev->udev, 0), cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, data, size, CONTROL_TIMEOUT_JIFFIES);}static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs){ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; if (urb->status < 0) printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", urb->status); kfree(req); usb_free_urb(urb);}static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs){ struct usbnet *dev = (struct usbnet *)urb->context; struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; int link; if (urb->status < 0) { printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d", urb->status); } else { if (data->int_buf[5] == 0x90) { link = data->int_buf[2] & 0x01; if (netif_carrier_ok(dev->net) != link) { if (link) netif_carrier_on(dev->net); else netif_carrier_off(dev->net); devdbg(dev, "ax8817x - Link Status is: %d", link); } } usb_submit_urb(data->int_urb, GFP_KERNEL); }}static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data){ struct usb_ctrlrequest *req; int status; struct urb *urb; if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) { devdbg(dev, "Error allocating URB in write_cmd_async!"); return; } if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) { deverr(dev, "Failed to allocate memory for control request"); usb_free_urb(urb); return; } req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; req->bRequest = cmd; req->wValue = cpu_to_le16(value); req->wIndex = cpu_to_le16(index); req->wLength = cpu_to_le16(size); usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (void *)req, data, size, ax8817x_async_cmd_callback, req); if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { deverr(dev, "Error submitting the control message: status=%d", status); kfree(req); usb_free_urb(urb); }}static void ax8817x_set_multicast(struct net_device *net){ struct usbnet *dev = (struct usbnet *) net->priv; struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; u8 rx_ctl = 0x8c; if (net->flags & IFF_PROMISC) { rx_ctl |= 0x01; } else if (net->flags & IFF_ALLMULTI || net->mc_count > AX_MAX_MCAST) { rx_ctl |= 0x02; } else if (net->mc_count == 0) { /* just broadcast and directed */ } else { /* We use the 20 byte dev->data * for our 8 byte filter buffer * to avoid allocating memory that * is tricky to free later */ struct dev_mc_list *mc_list = net->mc_list; u32 crc_bits; int i; memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); /* Build the multicast hash filter. */ for (i = 0; i < net->mc_count; i++) { crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); mc_list = mc_list->next; } ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, AX_MCAST_FILTER_SIZE, data->multi_filter); rx_ctl |= 0x10; } ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);}static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc){ struct usbnet *dev = netdev->priv; u16 res; u8 buf[1]; ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); return res & 0xffff;}static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val){ struct usbnet *dev = netdev->priv; u16 res = val; u8 buf[1]; ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);}static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo){ struct usbnet *dev = (struct usbnet *)net->priv; u8 opt; if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { wolinfo->supported = 0; wolinfo->wolopts = 0; return; } wolinfo->supported = WAKE_PHY | WAKE_MAGIC; wolinfo->wolopts = 0; if (opt & AX_MONITOR_MODE) { if (opt & AX_MONITOR_LINK) wolinfo->wolopts |= WAKE_PHY; if (opt & AX_MONITOR_MAGIC) wolinfo->wolopts |= WAKE_MAGIC; }}static int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo){ struct usbnet *dev = (struct usbnet *)net->priv; u8 opt = 0; u8 buf[1]; if (wolinfo->wolopts & WAKE_PHY) opt |= AX_MONITOR_LINK; if (wolinfo->wolopts & WAKE_MAGIC) opt |= AX_MONITOR_MAGIC; if (opt != 0) opt |= AX_MONITOR_MODE; if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, opt, 0, 0, &buf) < 0) return -EINVAL; return 0;}static int ax8817x_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data){ struct usbnet *dev = (struct usbnet *)net->priv; u16 *ebuf = (u16 *)data; int i; /* Crude hack to ensure that we don't overwrite memory * if an odd length is supplied */ if (eeprom->len % 2) return -EINVAL; /* ax8817x returns 2 bytes from eeprom on read */ for (i=0; i < eeprom->len / 2; i++) { if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, eeprom->offset + i, 0, 2, &ebuf[i]) < 0) return -EINVAL; } return i * 2;}static void ax8817x_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info){ /* Inherit standard device info */ usbnet_get_drvinfo(net, info); info->eedump_len = 0x3e;}static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd){ struct usbnet *dev = (struct usbnet *)net->priv; return mii_ethtool_gset(&dev->mii,cmd);}static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd){ struct usbnet *dev = (struct usbnet *)net->priv; return mii_ethtool_sset(&dev->mii,cmd);}/* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */static struct ethtool_ops ax8817x_ethtool_ops = { .get_drvinfo = ax8817x_get_drvinfo, .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = ax8817x_get_wol, .set_wol = ax8817x_set_wol, .get_eeprom = ax8817x_get_eeprom, .get_settings = ax8817x_get_settings, .set_settings = ax8817x_set_settings,};static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf){ int ret; u8 buf[6]; int i; unsigned long gpio_bits = dev->driver_info->data; struct ax8817x_data *data = (struct ax8817x_data *)dev->data; dev->in = usb_rcvbulkpipe(dev->udev, 3); dev->out = usb_sndbulkpipe(dev->udev, 2); // allocate irq urb if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { dbg ("%s: cannot allocate interrupt URB", dev->net->name); return -ENOMEM; } if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) { dbg ("%s: cannot allocate memory for interrupt buffer", dev->net->name); usb_free_urb(data->int_urb); return -ENOMEM; } memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE); usb_fill_int_urb (data->int_urb, dev->udev, usb_rcvintpipe (dev->udev, 1), data->int_buf, AX_INTERRUPT_BUFSIZE, ax8817x_interrupt_complete, dev, dev->udev->speed == USB_SPEED_HIGH ? 8 : 100); /* Toggle the GPIOs in a manufacturer/model specific way */ for (i = 2; i >= 0; i--) { if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, (gpio_bits >> (i * 8)) & 0xff, 0, 0, buf)) < 0) return ret; msleep(5); } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) { dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); return ret; } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); return ret; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); /* Get the PHY id */ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); return ret; } else if (ret < 2) { /* this should always return 2 bytes */ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); return -EIO; } /* Initialize MII structure */ dev->mii.dev = dev->net; dev->mii.mdio_read = ax8817x_mdio_read; dev->mii.mdio_write = ax8817x_mdio_write; dev->mii.phy_id_mask = 0x3f; dev->mii.reg_num_mask = 0x1f; dev->mii.phy_id = buf[1]; dev->net->set_multicast_list = ax8817x_set_multicast; dev->net->ethtool_ops = &ax8817x_ethtool_ops; ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, cpu_to_le16(BMCR_RESET)); ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400)); mii_nway_restart(&dev->mii); if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) { dbg("Failed to submit interrupt URB: %02x", ret); usb_free_urb(data->int_urb); return ret; } return 0;}static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf){ struct ax8817x_data *data = (struct ax8817x_data *)dev->data; usb_unlink_urb(data->int_urb); usb_free_urb(data->int_urb); kfree(data->int_buf);}static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", .bind = ax8817x_bind, .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x00130103,};static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", .bind = ax8817x_bind, .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x009f9d9f,};static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", .bind = ax8817x_bind, .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x00130103,};static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", .bind = ax8817x_bind, .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x001f1d1f,};#endif /* CONFIG_USB_AX8817X */#ifdef CONFIG_USB_BELKIN#define HAVE_HARDWARE/*------------------------------------------------------------------------- * * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller * * ... also two eTEK designs, including one sold as "Advance USBNET" * *-------------------------------------------------------------------------*/static const struct driver_info belkin_info = { .description = "Belkin, eTEK, or compatible",};#endif /* CONFIG_USB_BELKIN *//*------------------------------------------------------------------------- * * Communications Device Class declarations. * Used by CDC Ethernet, and some CDC variants * *-------------------------------------------------------------------------*/#ifdef CONFIG_USB_CDCETHER#define NEED_GENERIC_CDC#endif#ifdef CONFIG_USB_ZAURUS/* Ethernet variant uses funky framing, broken ethernet addressing */#define NEED_GENERIC_CDC#endif#ifdef CONFIG_USB_RNDIS/* ACM variant uses even funkier framing, complex control RPC scheme */#define NEED_GENERIC_CDC#endif#ifdef NEED_GENERIC_CDC/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */struct header_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u16 bcdCDC;} __attribute__ ((packed));/* "Union Functional Descriptor" from CDC spec 5.2.3.X */struct union_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 bMasterInterface0; u8 bSlaveInterface0; /* ... and there could be other slave interfaces */} __attribute__ ((packed));/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */struct ether_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 iMACAddress; u32 bmEthernetStatistics; __le16 wMaxSegmentSize; __le16 wNumberMCFilters; u8 bNumberPowerFilters;} __attribute__ ((packed));struct cdc_state { struct header_desc *header; struct union_desc *u; struct ether_desc *ether; struct usb_interface *control; struct usb_interface *data;};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?