| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet Devices |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2011-2013 ASIX |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version 2 |
|---|
| 9 | | - * of the License, or (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 | 6 | */ |
|---|
| 19 | 7 | |
|---|
| 20 | 8 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 43 | 31 | #define AX_ACCESS_PHY 0x02 |
|---|
| 44 | 32 | #define AX_ACCESS_EEPROM 0x04 |
|---|
| 45 | 33 | #define AX_ACCESS_EFUS 0x05 |
|---|
| 34 | +#define AX_RELOAD_EEPROM_EFUSE 0x06 |
|---|
| 46 | 35 | #define AX_PAUSE_WATERLVL_HIGH 0x54 |
|---|
| 47 | 36 | #define AX_PAUSE_WATERLVL_LOW 0x55 |
|---|
| 48 | 37 | |
|---|
| .. | .. |
|---|
| 623 | 612 | return 0; |
|---|
| 624 | 613 | } |
|---|
| 625 | 614 | |
|---|
| 615 | +static int |
|---|
| 616 | +ax88179_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, |
|---|
| 617 | + u8 *data) |
|---|
| 618 | +{ |
|---|
| 619 | + struct usbnet *dev = netdev_priv(net); |
|---|
| 620 | + u16 *eeprom_buff; |
|---|
| 621 | + int first_word; |
|---|
| 622 | + int last_word; |
|---|
| 623 | + int ret; |
|---|
| 624 | + int i; |
|---|
| 625 | + |
|---|
| 626 | + netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n", |
|---|
| 627 | + eeprom->len, eeprom->offset, eeprom->magic); |
|---|
| 628 | + |
|---|
| 629 | + if (eeprom->len == 0) |
|---|
| 630 | + return -EINVAL; |
|---|
| 631 | + |
|---|
| 632 | + if (eeprom->magic != AX88179_EEPROM_MAGIC) |
|---|
| 633 | + return -EINVAL; |
|---|
| 634 | + |
|---|
| 635 | + first_word = eeprom->offset >> 1; |
|---|
| 636 | + last_word = (eeprom->offset + eeprom->len - 1) >> 1; |
|---|
| 637 | + |
|---|
| 638 | + eeprom_buff = kmalloc_array(last_word - first_word + 1, sizeof(u16), |
|---|
| 639 | + GFP_KERNEL); |
|---|
| 640 | + if (!eeprom_buff) |
|---|
| 641 | + return -ENOMEM; |
|---|
| 642 | + |
|---|
| 643 | + /* align data to 16 bit boundaries, read the missing data from |
|---|
| 644 | + the EEPROM */ |
|---|
| 645 | + if (eeprom->offset & 1) { |
|---|
| 646 | + ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM, first_word, 1, 2, |
|---|
| 647 | + &eeprom_buff[0]); |
|---|
| 648 | + if (ret < 0) { |
|---|
| 649 | + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); |
|---|
| 650 | + goto free; |
|---|
| 651 | + } |
|---|
| 652 | + } |
|---|
| 653 | + |
|---|
| 654 | + if ((eeprom->offset + eeprom->len) & 1) { |
|---|
| 655 | + ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM, last_word, 1, 2, |
|---|
| 656 | + &eeprom_buff[last_word - first_word]); |
|---|
| 657 | + if (ret < 0) { |
|---|
| 658 | + netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); |
|---|
| 659 | + goto free; |
|---|
| 660 | + } |
|---|
| 661 | + } |
|---|
| 662 | + |
|---|
| 663 | + memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); |
|---|
| 664 | + |
|---|
| 665 | + for (i = first_word; i <= last_word; i++) { |
|---|
| 666 | + netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", |
|---|
| 667 | + i, eeprom_buff[i - first_word]); |
|---|
| 668 | + ret = ax88179_write_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2, |
|---|
| 669 | + &eeprom_buff[i - first_word]); |
|---|
| 670 | + if (ret < 0) { |
|---|
| 671 | + netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", i); |
|---|
| 672 | + goto free; |
|---|
| 673 | + } |
|---|
| 674 | + msleep(20); |
|---|
| 675 | + } |
|---|
| 676 | + |
|---|
| 677 | + /* reload EEPROM data */ |
|---|
| 678 | + ret = ax88179_write_cmd(dev, AX_RELOAD_EEPROM_EFUSE, 0x0000, 0, 0, NULL); |
|---|
| 679 | + if (ret < 0) { |
|---|
| 680 | + netdev_err(net, "Failed to reload EEPROM data\n"); |
|---|
| 681 | + goto free; |
|---|
| 682 | + } |
|---|
| 683 | + |
|---|
| 684 | + ret = 0; |
|---|
| 685 | +free: |
|---|
| 686 | + kfree(eeprom_buff); |
|---|
| 687 | + return ret; |
|---|
| 688 | +} |
|---|
| 689 | + |
|---|
| 626 | 690 | static int ax88179_get_link_ksettings(struct net_device *net, |
|---|
| 627 | 691 | struct ethtool_link_ksettings *cmd) |
|---|
| 628 | 692 | { |
|---|
| .. | .. |
|---|
| 796 | 860 | { |
|---|
| 797 | 861 | struct usbnet *dev = netdev_priv(net); |
|---|
| 798 | 862 | struct ax88179_data *priv = (struct ax88179_data *)dev->data; |
|---|
| 799 | | - int ret = -EOPNOTSUPP; |
|---|
| 863 | + int ret; |
|---|
| 800 | 864 | |
|---|
| 801 | 865 | priv->eee_enabled = edata->eee_enabled; |
|---|
| 802 | 866 | if (!priv->eee_enabled) { |
|---|
| .. | .. |
|---|
| 834 | 898 | .set_wol = ax88179_set_wol, |
|---|
| 835 | 899 | .get_eeprom_len = ax88179_get_eeprom_len, |
|---|
| 836 | 900 | .get_eeprom = ax88179_get_eeprom, |
|---|
| 901 | + .set_eeprom = ax88179_set_eeprom, |
|---|
| 837 | 902 | .get_eee = ax88179_get_eee, |
|---|
| 838 | 903 | .set_eee = ax88179_set_eee, |
|---|
| 839 | 904 | .nway_reset = usbnet_nway_reset, |
|---|
| 840 | 905 | .get_link_ksettings = ax88179_get_link_ksettings, |
|---|
| 841 | 906 | .set_link_ksettings = ax88179_set_link_ksettings, |
|---|
| 907 | + .get_ts_info = ethtool_op_get_ts_info, |
|---|
| 842 | 908 | }; |
|---|
| 843 | 909 | |
|---|
| 844 | 910 | static void ax88179_set_multicast(struct net_device *net) |
|---|
| .. | .. |
|---|
| 1226 | 1292 | return 0; |
|---|
| 1227 | 1293 | } |
|---|
| 1228 | 1294 | |
|---|
| 1295 | +static void ax88179_get_mac_addr(struct usbnet *dev) |
|---|
| 1296 | +{ |
|---|
| 1297 | + u8 mac[ETH_ALEN]; |
|---|
| 1298 | + |
|---|
| 1299 | + memset(mac, 0, sizeof(mac)); |
|---|
| 1300 | + |
|---|
| 1301 | + /* Maybe the boot loader passed the MAC address via device tree */ |
|---|
| 1302 | + if (!eth_platform_get_mac_address(&dev->udev->dev, mac)) { |
|---|
| 1303 | + netif_dbg(dev, ifup, dev->net, |
|---|
| 1304 | + "MAC address read from device tree"); |
|---|
| 1305 | + } else { |
|---|
| 1306 | + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, |
|---|
| 1307 | + ETH_ALEN, mac); |
|---|
| 1308 | + netif_dbg(dev, ifup, dev->net, |
|---|
| 1309 | + "MAC address read from ASIX chip"); |
|---|
| 1310 | + } |
|---|
| 1311 | + |
|---|
| 1312 | + if (is_valid_ether_addr(mac)) { |
|---|
| 1313 | + memcpy(dev->net->dev_addr, mac, ETH_ALEN); |
|---|
| 1314 | + } else { |
|---|
| 1315 | + netdev_info(dev->net, "invalid MAC address, using random\n"); |
|---|
| 1316 | + eth_hw_addr_random(dev->net); |
|---|
| 1317 | + } |
|---|
| 1318 | + |
|---|
| 1319 | + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, |
|---|
| 1320 | + dev->net->dev_addr); |
|---|
| 1321 | +} |
|---|
| 1322 | + |
|---|
| 1229 | 1323 | static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) |
|---|
| 1230 | 1324 | { |
|---|
| 1231 | 1325 | u8 buf[5]; |
|---|
| .. | .. |
|---|
| 1252 | 1346 | ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); |
|---|
| 1253 | 1347 | msleep(100); |
|---|
| 1254 | 1348 | |
|---|
| 1255 | | - ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, |
|---|
| 1256 | | - ETH_ALEN, dev->net->dev_addr); |
|---|
| 1349 | + /* Read MAC address from DTB or asix chip */ |
|---|
| 1350 | + ax88179_get_mac_addr(dev); |
|---|
| 1257 | 1351 | memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); |
|---|
| 1258 | 1352 | |
|---|
| 1259 | 1353 | /* RX bulk configuration */ |
|---|
| .. | .. |
|---|
| 1377 | 1471 | * are bundled into this buffer and where we can find an array of |
|---|
| 1378 | 1472 | * per-packet metadata (which contains elements encoded into u16). |
|---|
| 1379 | 1473 | */ |
|---|
| 1474 | + |
|---|
| 1475 | + /* SKB contents for current firmware: |
|---|
| 1476 | + * <packet 1> <padding> |
|---|
| 1477 | + * ... |
|---|
| 1478 | + * <packet N> <padding> |
|---|
| 1479 | + * <per-packet metadata entry 1> <dummy header> |
|---|
| 1480 | + * ... |
|---|
| 1481 | + * <per-packet metadata entry N> <dummy header> |
|---|
| 1482 | + * <padding2> <rx_hdr> |
|---|
| 1483 | + * |
|---|
| 1484 | + * where: |
|---|
| 1485 | + * <packet N> contains pkt_len bytes: |
|---|
| 1486 | + * 2 bytes of IP alignment pseudo header |
|---|
| 1487 | + * packet received |
|---|
| 1488 | + * <per-packet metadata entry N> contains 4 bytes: |
|---|
| 1489 | + * pkt_len and fields AX_RXHDR_* |
|---|
| 1490 | + * <padding> 0-7 bytes to terminate at |
|---|
| 1491 | + * 8 bytes boundary (64-bit). |
|---|
| 1492 | + * <padding2> 4 bytes to make rx_hdr terminate at |
|---|
| 1493 | + * 8 bytes boundary (64-bit) |
|---|
| 1494 | + * <dummy-header> contains 4 bytes: |
|---|
| 1495 | + * pkt_len=0 and AX_RXHDR_DROP_ERR |
|---|
| 1496 | + * <rx-hdr> contains 4 bytes: |
|---|
| 1497 | + * pkt_cnt and hdr_off (offset of |
|---|
| 1498 | + * <per-packet metadata entry 1>) |
|---|
| 1499 | + * |
|---|
| 1500 | + * pkt_cnt is number of entrys in the per-packet metadata. |
|---|
| 1501 | + * In current firmware there is 2 entrys per packet. |
|---|
| 1502 | + * The first points to the packet and the |
|---|
| 1503 | + * second is a dummy header. |
|---|
| 1504 | + * This was done probably to align fields in 64-bit and |
|---|
| 1505 | + * maintain compatibility with old firmware. |
|---|
| 1506 | + * This code assumes that <dummy header> and <padding2> are |
|---|
| 1507 | + * optional. |
|---|
| 1508 | + */ |
|---|
| 1509 | + |
|---|
| 1380 | 1510 | if (skb->len < 4) |
|---|
| 1381 | 1511 | return 0; |
|---|
| 1382 | 1512 | skb_trim(skb, skb->len - 4); |
|---|
| 1383 | | - memcpy(&rx_hdr, skb_tail_pointer(skb), 4); |
|---|
| 1384 | | - le32_to_cpus(&rx_hdr); |
|---|
| 1513 | + rx_hdr = get_unaligned_le32(skb_tail_pointer(skb)); |
|---|
| 1385 | 1514 | pkt_cnt = (u16)rx_hdr; |
|---|
| 1386 | 1515 | hdr_off = (u16)(rx_hdr >> 16); |
|---|
| 1387 | 1516 | |
|---|
| .. | .. |
|---|
| 1391 | 1520 | /* Make sure that the bounds of the metadata array are inside the SKB |
|---|
| 1392 | 1521 | * (and in front of the counter at the end). |
|---|
| 1393 | 1522 | */ |
|---|
| 1394 | | - if (pkt_cnt * 2 + hdr_off > skb->len) |
|---|
| 1523 | + if (pkt_cnt * 4 + hdr_off > skb->len) |
|---|
| 1395 | 1524 | return 0; |
|---|
| 1396 | 1525 | pkt_hdr = (u32 *)(skb->data + hdr_off); |
|---|
| 1397 | 1526 | |
|---|
| 1398 | 1527 | /* Packets must not overlap the metadata array */ |
|---|
| 1399 | 1528 | skb_trim(skb, hdr_off); |
|---|
| 1400 | 1529 | |
|---|
| 1401 | | - for (; ; pkt_cnt--, pkt_hdr++) { |
|---|
| 1530 | + for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) { |
|---|
| 1531 | + u16 pkt_len_plus_padd; |
|---|
| 1402 | 1532 | u16 pkt_len; |
|---|
| 1403 | 1533 | |
|---|
| 1404 | 1534 | le32_to_cpus(pkt_hdr); |
|---|
| 1405 | 1535 | pkt_len = (*pkt_hdr >> 16) & 0x1fff; |
|---|
| 1536 | + pkt_len_plus_padd = (pkt_len + 7) & 0xfff8; |
|---|
| 1406 | 1537 | |
|---|
| 1407 | | - if (pkt_len > skb->len) |
|---|
| 1538 | + /* Skip dummy header used for alignment |
|---|
| 1539 | + */ |
|---|
| 1540 | + if (pkt_len == 0) |
|---|
| 1541 | + continue; |
|---|
| 1542 | + |
|---|
| 1543 | + if (pkt_len_plus_padd > skb->len) |
|---|
| 1408 | 1544 | return 0; |
|---|
| 1409 | 1545 | |
|---|
| 1410 | 1546 | /* Check CRC or runt packet */ |
|---|
| 1411 | | - if (((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) == 0) && |
|---|
| 1412 | | - pkt_len >= 2 + ETH_HLEN) { |
|---|
| 1413 | | - bool last = (pkt_cnt == 0); |
|---|
| 1414 | | - |
|---|
| 1415 | | - if (last) { |
|---|
| 1416 | | - ax_skb = skb; |
|---|
| 1417 | | - } else { |
|---|
| 1418 | | - ax_skb = skb_clone(skb, GFP_ATOMIC); |
|---|
| 1419 | | - if (!ax_skb) |
|---|
| 1420 | | - return 0; |
|---|
| 1421 | | - } |
|---|
| 1422 | | - ax_skb->len = pkt_len; |
|---|
| 1423 | | - /* Skip IP alignment pseudo header */ |
|---|
| 1424 | | - skb_pull(ax_skb, 2); |
|---|
| 1425 | | - skb_set_tail_pointer(ax_skb, ax_skb->len); |
|---|
| 1426 | | - ax_skb->truesize = pkt_len + sizeof(struct sk_buff); |
|---|
| 1427 | | - ax88179_rx_checksum(ax_skb, pkt_hdr); |
|---|
| 1428 | | - |
|---|
| 1429 | | - if (last) |
|---|
| 1430 | | - return 1; |
|---|
| 1431 | | - |
|---|
| 1432 | | - usbnet_skb_return(dev, ax_skb); |
|---|
| 1547 | + if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) || |
|---|
| 1548 | + pkt_len < 2 + ETH_HLEN) { |
|---|
| 1549 | + dev->net->stats.rx_errors++; |
|---|
| 1550 | + skb_pull(skb, pkt_len_plus_padd); |
|---|
| 1551 | + continue; |
|---|
| 1433 | 1552 | } |
|---|
| 1434 | 1553 | |
|---|
| 1435 | | - /* Trim this packet away from the SKB */ |
|---|
| 1436 | | - if (!skb_pull(skb, (pkt_len + 7) & 0xFFF8)) |
|---|
| 1554 | + /* last packet */ |
|---|
| 1555 | + if (pkt_len_plus_padd == skb->len) { |
|---|
| 1556 | + skb_trim(skb, pkt_len); |
|---|
| 1557 | + |
|---|
| 1558 | + /* Skip IP alignment pseudo header */ |
|---|
| 1559 | + skb_pull(skb, 2); |
|---|
| 1560 | + |
|---|
| 1561 | + skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd); |
|---|
| 1562 | + ax88179_rx_checksum(skb, pkt_hdr); |
|---|
| 1563 | + return 1; |
|---|
| 1564 | + } |
|---|
| 1565 | + |
|---|
| 1566 | + ax_skb = skb_clone(skb, GFP_ATOMIC); |
|---|
| 1567 | + if (!ax_skb) |
|---|
| 1437 | 1568 | return 0; |
|---|
| 1569 | + skb_trim(ax_skb, pkt_len); |
|---|
| 1570 | + |
|---|
| 1571 | + /* Skip IP alignment pseudo header */ |
|---|
| 1572 | + skb_pull(ax_skb, 2); |
|---|
| 1573 | + |
|---|
| 1574 | + skb->truesize = pkt_len_plus_padd + |
|---|
| 1575 | + SKB_DATA_ALIGN(sizeof(struct sk_buff)); |
|---|
| 1576 | + ax88179_rx_checksum(ax_skb, pkt_hdr); |
|---|
| 1577 | + usbnet_skb_return(dev, ax_skb); |
|---|
| 1578 | + |
|---|
| 1579 | + skb_pull(skb, pkt_len_plus_padd); |
|---|
| 1438 | 1580 | } |
|---|
| 1581 | + |
|---|
| 1582 | + return 0; |
|---|
| 1439 | 1583 | } |
|---|
| 1440 | 1584 | |
|---|
| 1441 | 1585 | static struct sk_buff * |
|---|
| .. | .. |
|---|
| 1445 | 1589 | int frame_size = dev->maxpacket; |
|---|
| 1446 | 1590 | int mss = skb_shinfo(skb)->gso_size; |
|---|
| 1447 | 1591 | int headroom; |
|---|
| 1592 | + void *ptr; |
|---|
| 1448 | 1593 | |
|---|
| 1449 | 1594 | tx_hdr1 = skb->len; |
|---|
| 1450 | 1595 | tx_hdr2 = mss; |
|---|
| .. | .. |
|---|
| 1459 | 1604 | return NULL; |
|---|
| 1460 | 1605 | } |
|---|
| 1461 | 1606 | |
|---|
| 1462 | | - skb_push(skb, 4); |
|---|
| 1463 | | - cpu_to_le32s(&tx_hdr2); |
|---|
| 1464 | | - skb_copy_to_linear_data(skb, &tx_hdr2, 4); |
|---|
| 1465 | | - |
|---|
| 1466 | | - skb_push(skb, 4); |
|---|
| 1467 | | - cpu_to_le32s(&tx_hdr1); |
|---|
| 1468 | | - skb_copy_to_linear_data(skb, &tx_hdr1, 4); |
|---|
| 1607 | + ptr = skb_push(skb, 8); |
|---|
| 1608 | + put_unaligned_le32(tx_hdr1, ptr); |
|---|
| 1609 | + put_unaligned_le32(tx_hdr2, ptr + 4); |
|---|
| 1469 | 1610 | |
|---|
| 1470 | 1611 | return skb; |
|---|
| 1471 | 1612 | } |
|---|
| .. | .. |
|---|
| 1568 | 1709 | /* Ethernet PHY Auto Detach*/ |
|---|
| 1569 | 1710 | ax88179_auto_detach(dev, 0); |
|---|
| 1570 | 1711 | |
|---|
| 1571 | | - ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, |
|---|
| 1572 | | - dev->net->dev_addr); |
|---|
| 1712 | + /* Read MAC address from DTB or asix chip */ |
|---|
| 1713 | + ax88179_get_mac_addr(dev); |
|---|
| 1573 | 1714 | |
|---|
| 1574 | 1715 | /* RX bulk configuration */ |
|---|
| 1575 | 1716 | memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); |
|---|
| .. | .. |
|---|
| 1751 | 1892 | .tx_fixup = ax88179_tx_fixup, |
|---|
| 1752 | 1893 | }; |
|---|
| 1753 | 1894 | |
|---|
| 1895 | +static const struct driver_info toshiba_info = { |
|---|
| 1896 | + .description = "Toshiba USB Ethernet Adapter", |
|---|
| 1897 | + .bind = ax88179_bind, |
|---|
| 1898 | + .unbind = ax88179_unbind, |
|---|
| 1899 | + .status = ax88179_status, |
|---|
| 1900 | + .link_reset = ax88179_link_reset, |
|---|
| 1901 | + .reset = ax88179_reset, |
|---|
| 1902 | + .stop = ax88179_stop, |
|---|
| 1903 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
|---|
| 1904 | + .rx_fixup = ax88179_rx_fixup, |
|---|
| 1905 | + .tx_fixup = ax88179_tx_fixup, |
|---|
| 1906 | +}; |
|---|
| 1907 | + |
|---|
| 1908 | +static const struct driver_info mct_info = { |
|---|
| 1909 | + .description = "MCT USB 3.0 Gigabit Ethernet Adapter", |
|---|
| 1910 | + .bind = ax88179_bind, |
|---|
| 1911 | + .unbind = ax88179_unbind, |
|---|
| 1912 | + .status = ax88179_status, |
|---|
| 1913 | + .link_reset = ax88179_link_reset, |
|---|
| 1914 | + .reset = ax88179_reset, |
|---|
| 1915 | + .stop = ax88179_stop, |
|---|
| 1916 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
|---|
| 1917 | + .rx_fixup = ax88179_rx_fixup, |
|---|
| 1918 | + .tx_fixup = ax88179_tx_fixup, |
|---|
| 1919 | +}; |
|---|
| 1920 | + |
|---|
| 1754 | 1921 | static const struct usb_device_id products[] = { |
|---|
| 1755 | 1922 | { |
|---|
| 1756 | 1923 | /* ASIX AX88179 10/100/1000 */ |
|---|
| .. | .. |
|---|
| 1784 | 1951 | /* Belkin B2B128 USB 3.0 Hub + Gigabit Ethernet Adapter */ |
|---|
| 1785 | 1952 | USB_DEVICE(0x050d, 0x0128), |
|---|
| 1786 | 1953 | .driver_info = (unsigned long)&belkin_info, |
|---|
| 1954 | +}, { |
|---|
| 1955 | + /* Toshiba USB 3.0 GBit Ethernet Adapter */ |
|---|
| 1956 | + USB_DEVICE(0x0930, 0x0a13), |
|---|
| 1957 | + .driver_info = (unsigned long)&toshiba_info, |
|---|
| 1958 | +}, { |
|---|
| 1959 | + /* Magic Control Technology U3-A9003 USB 3.0 Gigabit Ethernet Adapter */ |
|---|
| 1960 | + USB_DEVICE(0x0711, 0x0179), |
|---|
| 1961 | + .driver_info = (unsigned long)&mct_info, |
|---|
| 1787 | 1962 | }, |
|---|
| 1788 | 1963 | { }, |
|---|
| 1789 | 1964 | }; |
|---|