📄 asix.c
字号:
0, 0, 6, buf)) < 0) { dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); goto out2; } 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); goto out2; } else if (ret < 2) { /* this should always return 2 bytes */ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); ret = -EIO; goto out2; } /* 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 = *((u8 *)buf + 1); dev->net->do_ioctl = ax8817x_ioctl; dev->net->set_multicast_list = ax8817x_set_multicast; dev->net->ethtool_ops = &ax8817x_ethtool_ops; ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); return 0;out2: kfree(buf);out1: return ret;}static struct ethtool_ops ax88772_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_len = ax8817x_get_eeprom_len, .get_eeprom = ax8817x_get_eeprom, .get_settings = ax8817x_get_settings, .set_settings = ax8817x_set_settings,};static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf){ int ret; void *buf; usbnet_get_endpoints(dev,intf); buf = kmalloc(6, GFP_KERNEL); if(!buf) { dbg ("Cannot allocate memory for buffer"); ret = -ENOMEM; goto out1; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, buf)) < 0) goto out2; msleep(5); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, 0, 0, buf)) < 0) { dbg("Failed to power down internal PHY: %d", ret); goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, 0, 0, buf)) < 0) { dbg("Failed to perform software reset: %d", ret); goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Failed to set Internal/External PHY reset control: %d", ret); goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0000, 0, 0, buf)) < 0) { dbg("Failed to reset RX_CTL: %d", ret); goto out2; } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { dbg("Failed to read MAC address: %d", ret); goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, buf)) < 0) { dbg("Enabling software MII failed: %d", ret); goto out2; } if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) || (*((u16 *)buf) != 0x003b)) { dbg("Read PHY register 2 must be 0x3b00: %d", ret); goto out2; } /* 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 = 0xff; dev->mii.reg_num_mask = 0xff; dev->net->do_ioctl = ax8817x_ioctl; /* Get the PHY id */ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf)) < 0) { dbg("Error reading PHY ID: %02x", ret); goto out2; } else if (ret < 2) { /* this should always return 2 bytes */ dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", ret); ret = -EIO; goto out2; } dev->mii.phy_id = *((u8 *)buf + 1); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Set external PHY reset pin level: %d", ret); goto out2; } msleep(150); if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | AX_SWRESET_PRL, 0, 0, buf)) < 0) { dbg("Set Internal/External PHY reset control: %d", ret); goto out2; } msleep(150); dev->net->set_multicast_list = ax8817x_set_multicast; dev->net->ethtool_ops = &ax88772_ethtool_ops; ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(&dev->mii); if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { dbg("Write medium mode register: %d", ret); goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG2_DEFAULT, 0, buf)) < 0) { dbg("Write IPG,IPG1,IPG2 failed: %d", ret); goto out2; } if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { dbg("Failed to set hardware MII: %02x", ret); goto out2; } /* Set RX_CTL to default values with 2k buffer, and enable cactus */ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, buf)) < 0) { dbg("Reset RX_CTL failed: %d", ret); goto out2; } kfree(buf); /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ if (dev->driver_info->flags & FLAG_FRAMING_AX) { /* hard_mtu is still the default - the device does not support jumbo eth frames */ dev->rx_urb_size = 2048; } return 0;out2: kfree(buf);out1: return ret;}static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb){ u8 *head; u32 header; char *packet; struct sk_buff *ax_skb; u16 size; head = (u8 *) skb->data; memcpy(&header, head, sizeof(header)); le32_to_cpus(&header); packet = head + sizeof(header); skb_pull(skb, 4); while (skb->len > 0) { if ((short)(header & 0x0000ffff) != ~((short)((header & 0xffff0000) >> 16))) { devdbg(dev,"header length data is error"); } /* get the packet length */ size = (u16) (header & 0x0000ffff); if ((skb->len) - ((size + 1) & 0xfffe) == 0) return 2; if (size > ETH_FRAME_LEN) { devdbg(dev,"invalid rx length %d", size); return 0; } ax_skb = skb_clone(skb, GFP_ATOMIC); if (ax_skb) { ax_skb->len = size; ax_skb->data = packet; ax_skb->tail = packet + size; usbnet_skb_return(dev, ax_skb); } else { return 0; } skb_pull(skb, (size + 1) & 0xfffe); if (skb->len == 0) break; head = (u8 *) skb->data; memcpy(&header, head, sizeof(header)); le32_to_cpus(&header); packet = head + sizeof(header); skb_pull(skb, 4); } if (skb->len < 0) { devdbg(dev,"invalid rx length %d", skb->len); return 0; } return 1;}static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags){ int padlen; int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); u32 packet_len; u32 padbytes = 0xffff0000; padlen = ((skb->len + 4) % 512) ? 0 : 4; if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { if ((headroom < 4) || (tailroom < padlen)) { skb->data = memmove(skb->head + 4, skb->data, skb->len); skb->tail = skb->data + skb->len; } } else { struct sk_buff *skb2; skb2 = skb_copy_expand(skb, 4, padlen, flags); dev_kfree_skb_any(skb); skb = skb2; if (!skb) return NULL; } skb_push(skb, 4); packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); memcpy(skb->data, &packet_len, sizeof(packet_len)); if ((skb->len % 512) == 0) { memcpy( skb->tail, &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); } return skb;}static int ax88772_link_reset(struct usbnet *dev){ u16 lpa; u16 adv; u16 res; u16 mode; mode = AX88772_MEDIUM_DEFAULT; lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); res = mii_nway_result(lpa|adv); if ((res & LPA_DUPLEX) == 0) mode &= ~AX88772_MEDIUM_FULL_DUPLEX; if ((res & LPA_100) == 0) mode &= ~AX88772_MEDIUM_100MB; ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); return 0;}static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", .bind = ax8817x_bind, .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x00130103,};static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", .bind = ax8817x_bind, .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x009f9d9f,};static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", .bind = ax8817x_bind, .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x00130103,};static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", .bind = ax8817x_bind, .status = ax8817x_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, .data = 0x001f1d1f,};static const struct driver_info ax88772_info = { .description = "ASIX AX88772 USB 2.0 Ethernet", .bind = ax88772_bind, .status = ax8817x_status, .link_reset = ax88772_link_reset, .reset = ax88772_link_reset, .flags = FLAG_ETHER | FLAG_FRAMING_AX, .rx_fixup = ax88772_rx_fixup, .tx_fixup = ax88772_tx_fixup, .data = 0x00130103,};static const struct usb_device_id products [] = {{ // Linksys USB200M USB_DEVICE (0x077b, 0x2226), .driver_info = (unsigned long) &ax8817x_info,}, { // Netgear FA120 USB_DEVICE (0x0846, 0x1040), .driver_info = (unsigned long) &netgear_fa120_info,}, { // DLink DUB-E100 USB_DEVICE (0x2001, 0x1a00), .driver_info = (unsigned long) &dlink_dub_e100_info,}, { // Intellinet, ST Lab USB Ethernet USB_DEVICE (0x0b95, 0x1720), .driver_info = (unsigned long) &ax8817x_info,}, { // Hawking UF200, TrendNet TU2-ET100 USB_DEVICE (0x07b8, 0x420a), .driver_info = (unsigned long) &hawking_uf200_info,}, { // Billionton Systems, USB2AR USB_DEVICE (0x08dd, 0x90ff), .driver_info = (unsigned long) &ax8817x_info,}, { // ATEN UC210T USB_DEVICE (0x0557, 0x2009), .driver_info = (unsigned long) &ax8817x_info,}, { // Buffalo LUA-U2-KTX USB_DEVICE (0x0411, 0x003d), .driver_info = (unsigned long) &ax8817x_info,}, { // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" USB_DEVICE (0x6189, 0x182d), .driver_info = (unsigned long) &ax8817x_info,}, { // corega FEther USB2-TX USB_DEVICE (0x07aa, 0x0017), .driver_info = (unsigned long) &ax8817x_info,}, { // Surecom EP-1427X-2 USB_DEVICE (0x1189, 0x0893), .driver_info = (unsigned long) &ax8817x_info,}, { // goodway corp usb gwusb2e USB_DEVICE (0x1631, 0x6200), .driver_info = (unsigned long) &ax8817x_info,}, { // ASIX AX88772 10/100 USB_DEVICE (0x0b95, 0x7720), .driver_info = (unsigned long) &ax88772_info,}, { }, // END};MODULE_DEVICE_TABLE(usb, products);static struct usb_driver asix_driver = { .owner = THIS_MODULE, .name = "asix", .id_table = products, .probe = usbnet_probe, .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect,};static int __init asix_init(void){ return usb_register(&asix_driver);}module_init(asix_init);static void __exit asix_exit(void){ usb_deregister(&asix_driver);}module_exit(asix_exit);MODULE_AUTHOR("David Hollis");MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -