1c9b37458SLiu Junliang /* 2c9b37458SLiu Junliang * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices 3c9b37458SLiu Junliang * 4c9b37458SLiu Junliang * Author : Liu Junliang <liujunliang_ljl@163.com> 5c9b37458SLiu Junliang * 6c9b37458SLiu Junliang * Based on dm9601.c 7c9b37458SLiu Junliang * 8c9b37458SLiu Junliang * This file is licensed under the terms of the GNU General Public License 9c9b37458SLiu Junliang * version 2. This program is licensed "as is" without any warranty of any 10c9b37458SLiu Junliang * kind, whether express or implied. 11c9b37458SLiu Junliang */ 12c9b37458SLiu Junliang 13c9b37458SLiu Junliang #include <linux/module.h> 14c9b37458SLiu Junliang #include <linux/sched.h> 15c9b37458SLiu Junliang #include <linux/stddef.h> 16c9b37458SLiu Junliang #include <linux/netdevice.h> 17c9b37458SLiu Junliang #include <linux/etherdevice.h> 18c9b37458SLiu Junliang #include <linux/ethtool.h> 19c9b37458SLiu Junliang #include <linux/mii.h> 20c9b37458SLiu Junliang #include <linux/usb.h> 21c9b37458SLiu Junliang #include <linux/crc32.h> 22c9b37458SLiu Junliang #include <linux/usb/usbnet.h> 23c9b37458SLiu Junliang 24c9b37458SLiu Junliang #include "sr9700.h" 25c9b37458SLiu Junliang 26c9b37458SLiu Junliang static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data) 27c9b37458SLiu Junliang { 28c9b37458SLiu Junliang int err; 29c9b37458SLiu Junliang 30c9b37458SLiu Junliang err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data, 31c9b37458SLiu Junliang length); 32c9b37458SLiu Junliang if ((err != length) && (err >= 0)) 33c9b37458SLiu Junliang err = -EINVAL; 34c9b37458SLiu Junliang return err; 35c9b37458SLiu Junliang } 36c9b37458SLiu Junliang 37c9b37458SLiu Junliang static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data) 38c9b37458SLiu Junliang { 39c9b37458SLiu Junliang int err; 40c9b37458SLiu Junliang 41c9b37458SLiu Junliang err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data, 42c9b37458SLiu Junliang length); 43c9b37458SLiu Junliang if ((err >= 0) && (err < length)) 44c9b37458SLiu Junliang err = -EINVAL; 45c9b37458SLiu Junliang return err; 46c9b37458SLiu Junliang } 47c9b37458SLiu Junliang 48c9b37458SLiu Junliang static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) 49c9b37458SLiu Junliang { 50c9b37458SLiu Junliang return sr_read(dev, reg, 1, value); 51c9b37458SLiu Junliang } 52c9b37458SLiu Junliang 53c9b37458SLiu Junliang static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) 54c9b37458SLiu Junliang { 55c9b37458SLiu Junliang return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 56c9b37458SLiu Junliang value, reg, NULL, 0); 57c9b37458SLiu Junliang } 58c9b37458SLiu Junliang 59c9b37458SLiu Junliang static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) 60c9b37458SLiu Junliang { 61c9b37458SLiu Junliang usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, 62c9b37458SLiu Junliang 0, reg, data, length); 63c9b37458SLiu Junliang } 64c9b37458SLiu Junliang 65c9b37458SLiu Junliang static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) 66c9b37458SLiu Junliang { 67c9b37458SLiu Junliang usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, 68c9b37458SLiu Junliang value, reg, NULL, 0); 69c9b37458SLiu Junliang } 70c9b37458SLiu Junliang 71c9b37458SLiu Junliang static int wait_phy_eeprom_ready(struct usbnet *dev, int phy) 72c9b37458SLiu Junliang { 73c9b37458SLiu Junliang int i; 74c9b37458SLiu Junliang 75c9b37458SLiu Junliang for (i = 0; i < SR_SHARE_TIMEOUT; i++) { 76c9b37458SLiu Junliang u8 tmp = 0; 77c9b37458SLiu Junliang int ret; 78c9b37458SLiu Junliang 79c9b37458SLiu Junliang udelay(1); 80*06b19b1bSChen Gang ret = sr_read_reg(dev, SR_EPCR, &tmp); 81c9b37458SLiu Junliang if (ret < 0) 82c9b37458SLiu Junliang return ret; 83c9b37458SLiu Junliang 84c9b37458SLiu Junliang /* ready */ 85c9b37458SLiu Junliang if (!(tmp & EPCR_ERRE)) 86c9b37458SLiu Junliang return 0; 87c9b37458SLiu Junliang } 88c9b37458SLiu Junliang 89c9b37458SLiu Junliang netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom"); 90c9b37458SLiu Junliang 91c9b37458SLiu Junliang return -EIO; 92c9b37458SLiu Junliang } 93c9b37458SLiu Junliang 94c9b37458SLiu Junliang static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, 95c9b37458SLiu Junliang __le16 *value) 96c9b37458SLiu Junliang { 97c9b37458SLiu Junliang int ret; 98c9b37458SLiu Junliang 99c9b37458SLiu Junliang mutex_lock(&dev->phy_mutex); 100c9b37458SLiu Junliang 101*06b19b1bSChen Gang sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); 102*06b19b1bSChen Gang sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR); 103c9b37458SLiu Junliang 104c9b37458SLiu Junliang ret = wait_phy_eeprom_ready(dev, phy); 105c9b37458SLiu Junliang if (ret < 0) 106c9b37458SLiu Junliang goto out_unlock; 107c9b37458SLiu Junliang 108*06b19b1bSChen Gang sr_write_reg(dev, SR_EPCR, 0x0); 109*06b19b1bSChen Gang ret = sr_read(dev, SR_EPDR, 2, value); 110c9b37458SLiu Junliang 111c9b37458SLiu Junliang netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", 112c9b37458SLiu Junliang phy, reg, *value, ret); 113c9b37458SLiu Junliang 114c9b37458SLiu Junliang out_unlock: 115c9b37458SLiu Junliang mutex_unlock(&dev->phy_mutex); 116c9b37458SLiu Junliang return ret; 117c9b37458SLiu Junliang } 118c9b37458SLiu Junliang 119c9b37458SLiu Junliang static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, 120c9b37458SLiu Junliang __le16 value) 121c9b37458SLiu Junliang { 122c9b37458SLiu Junliang int ret; 123c9b37458SLiu Junliang 124c9b37458SLiu Junliang mutex_lock(&dev->phy_mutex); 125c9b37458SLiu Junliang 126*06b19b1bSChen Gang ret = sr_write(dev, SR_EPDR, 2, &value); 127c9b37458SLiu Junliang if (ret < 0) 128c9b37458SLiu Junliang goto out_unlock; 129c9b37458SLiu Junliang 130*06b19b1bSChen Gang sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); 131*06b19b1bSChen Gang sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) : 132c9b37458SLiu Junliang (EPCR_WEP | EPCR_ERPRW)); 133c9b37458SLiu Junliang 134c9b37458SLiu Junliang ret = wait_phy_eeprom_ready(dev, phy); 135c9b37458SLiu Junliang if (ret < 0) 136c9b37458SLiu Junliang goto out_unlock; 137c9b37458SLiu Junliang 138*06b19b1bSChen Gang sr_write_reg(dev, SR_EPCR, 0x0); 139c9b37458SLiu Junliang 140c9b37458SLiu Junliang out_unlock: 141c9b37458SLiu Junliang mutex_unlock(&dev->phy_mutex); 142c9b37458SLiu Junliang return ret; 143c9b37458SLiu Junliang } 144c9b37458SLiu Junliang 145c9b37458SLiu Junliang static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) 146c9b37458SLiu Junliang { 147c9b37458SLiu Junliang return sr_share_read_word(dev, 0, offset, value); 148c9b37458SLiu Junliang } 149c9b37458SLiu Junliang 150c9b37458SLiu Junliang static int sr9700_get_eeprom_len(struct net_device *netdev) 151c9b37458SLiu Junliang { 152c9b37458SLiu Junliang return SR_EEPROM_LEN; 153c9b37458SLiu Junliang } 154c9b37458SLiu Junliang 155c9b37458SLiu Junliang static int sr9700_get_eeprom(struct net_device *netdev, 156c9b37458SLiu Junliang struct ethtool_eeprom *eeprom, u8 *data) 157c9b37458SLiu Junliang { 158c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 159c9b37458SLiu Junliang __le16 *buf = (__le16 *)data; 160c9b37458SLiu Junliang int ret = 0; 161c9b37458SLiu Junliang int i; 162c9b37458SLiu Junliang 163c9b37458SLiu Junliang /* access is 16bit */ 164c9b37458SLiu Junliang if ((eeprom->offset & 0x01) || (eeprom->len & 0x01)) 165c9b37458SLiu Junliang return -EINVAL; 166c9b37458SLiu Junliang 167c9b37458SLiu Junliang for (i = 0; i < eeprom->len / 2; i++) { 168c9b37458SLiu Junliang ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i); 169c9b37458SLiu Junliang if (ret < 0) 170c9b37458SLiu Junliang break; 171c9b37458SLiu Junliang } 172c9b37458SLiu Junliang 173c9b37458SLiu Junliang return ret; 174c9b37458SLiu Junliang } 175c9b37458SLiu Junliang 176c9b37458SLiu Junliang static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) 177c9b37458SLiu Junliang { 178c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 179c9b37458SLiu Junliang __le16 res; 180c9b37458SLiu Junliang int rc = 0; 181c9b37458SLiu Junliang 182c9b37458SLiu Junliang if (phy_id) { 183c9b37458SLiu Junliang netdev_dbg(netdev, "Only internal phy supported\n"); 184c9b37458SLiu Junliang return 0; 185c9b37458SLiu Junliang } 186c9b37458SLiu Junliang 187c9b37458SLiu Junliang /* Access NSR_LINKST bit for link status instead of MII_BMSR */ 188c9b37458SLiu Junliang if (loc == MII_BMSR) { 189c9b37458SLiu Junliang u8 value; 190c9b37458SLiu Junliang 191*06b19b1bSChen Gang sr_read_reg(dev, SR_NSR, &value); 192c9b37458SLiu Junliang if (value & NSR_LINKST) 193c9b37458SLiu Junliang rc = 1; 194c9b37458SLiu Junliang } 195c9b37458SLiu Junliang sr_share_read_word(dev, 1, loc, &res); 196c9b37458SLiu Junliang if (rc == 1) 197c9b37458SLiu Junliang res = le16_to_cpu(res) | BMSR_LSTATUS; 198c9b37458SLiu Junliang else 199c9b37458SLiu Junliang res = le16_to_cpu(res) & ~BMSR_LSTATUS; 200c9b37458SLiu Junliang 201c9b37458SLiu Junliang netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 202c9b37458SLiu Junliang phy_id, loc, res); 203c9b37458SLiu Junliang 204c9b37458SLiu Junliang return res; 205c9b37458SLiu Junliang } 206c9b37458SLiu Junliang 207c9b37458SLiu Junliang static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, 208c9b37458SLiu Junliang int val) 209c9b37458SLiu Junliang { 210c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 211c9b37458SLiu Junliang __le16 res = cpu_to_le16(val); 212c9b37458SLiu Junliang 213c9b37458SLiu Junliang if (phy_id) { 214c9b37458SLiu Junliang netdev_dbg(netdev, "Only internal phy supported\n"); 215c9b37458SLiu Junliang return; 216c9b37458SLiu Junliang } 217c9b37458SLiu Junliang 218c9b37458SLiu Junliang netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 219c9b37458SLiu Junliang phy_id, loc, val); 220c9b37458SLiu Junliang 221c9b37458SLiu Junliang sr_share_write_word(dev, 1, loc, res); 222c9b37458SLiu Junliang } 223c9b37458SLiu Junliang 224c9b37458SLiu Junliang static u32 sr9700_get_link(struct net_device *netdev) 225c9b37458SLiu Junliang { 226c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 227c9b37458SLiu Junliang u8 value = 0; 228c9b37458SLiu Junliang int rc = 0; 229c9b37458SLiu Junliang 230c9b37458SLiu Junliang /* Get the Link Status directly */ 231*06b19b1bSChen Gang sr_read_reg(dev, SR_NSR, &value); 232c9b37458SLiu Junliang if (value & NSR_LINKST) 233c9b37458SLiu Junliang rc = 1; 234c9b37458SLiu Junliang 235c9b37458SLiu Junliang return rc; 236c9b37458SLiu Junliang } 237c9b37458SLiu Junliang 238c9b37458SLiu Junliang static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 239c9b37458SLiu Junliang { 240c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 241c9b37458SLiu Junliang 242c9b37458SLiu Junliang return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); 243c9b37458SLiu Junliang } 244c9b37458SLiu Junliang 245c9b37458SLiu Junliang static const struct ethtool_ops sr9700_ethtool_ops = { 246c9b37458SLiu Junliang .get_drvinfo = usbnet_get_drvinfo, 247c9b37458SLiu Junliang .get_link = sr9700_get_link, 248c9b37458SLiu Junliang .get_msglevel = usbnet_get_msglevel, 249c9b37458SLiu Junliang .set_msglevel = usbnet_set_msglevel, 250c9b37458SLiu Junliang .get_eeprom_len = sr9700_get_eeprom_len, 251c9b37458SLiu Junliang .get_eeprom = sr9700_get_eeprom, 252c9b37458SLiu Junliang .get_settings = usbnet_get_settings, 253c9b37458SLiu Junliang .set_settings = usbnet_set_settings, 254c9b37458SLiu Junliang .nway_reset = usbnet_nway_reset, 255c9b37458SLiu Junliang }; 256c9b37458SLiu Junliang 257c9b37458SLiu Junliang static void sr9700_set_multicast(struct net_device *netdev) 258c9b37458SLiu Junliang { 259c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 260c9b37458SLiu Junliang /* We use the 20 byte dev->data for our 8 byte filter buffer 261c9b37458SLiu Junliang * to avoid allocating memory that is tricky to free later 262c9b37458SLiu Junliang */ 263c9b37458SLiu Junliang u8 *hashes = (u8 *)&dev->data; 264c9b37458SLiu Junliang /* rx_ctl setting : enable, disable_long, disable_crc */ 265c9b37458SLiu Junliang u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG; 266c9b37458SLiu Junliang 267c9b37458SLiu Junliang memset(hashes, 0x00, SR_MCAST_SIZE); 268c9b37458SLiu Junliang /* broadcast address */ 269c9b37458SLiu Junliang hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG; 270c9b37458SLiu Junliang if (netdev->flags & IFF_PROMISC) { 271c9b37458SLiu Junliang rx_ctl |= RCR_PRMSC; 272c9b37458SLiu Junliang } else if (netdev->flags & IFF_ALLMULTI || 273c9b37458SLiu Junliang netdev_mc_count(netdev) > SR_MCAST_MAX) { 274c9b37458SLiu Junliang rx_ctl |= RCR_RUNT; 275c9b37458SLiu Junliang } else if (!netdev_mc_empty(netdev)) { 276c9b37458SLiu Junliang struct netdev_hw_addr *ha; 277c9b37458SLiu Junliang 278c9b37458SLiu Junliang netdev_for_each_mc_addr(ha, netdev) { 279c9b37458SLiu Junliang u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26; 280c9b37458SLiu Junliang hashes[crc >> 3] |= 1 << (crc & 0x7); 281c9b37458SLiu Junliang } 282c9b37458SLiu Junliang } 283c9b37458SLiu Junliang 284*06b19b1bSChen Gang sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes); 285*06b19b1bSChen Gang sr_write_reg_async(dev, SR_RCR, rx_ctl); 286c9b37458SLiu Junliang } 287c9b37458SLiu Junliang 288c9b37458SLiu Junliang static int sr9700_set_mac_address(struct net_device *netdev, void *p) 289c9b37458SLiu Junliang { 290c9b37458SLiu Junliang struct usbnet *dev = netdev_priv(netdev); 291c9b37458SLiu Junliang struct sockaddr *addr = p; 292c9b37458SLiu Junliang 293c9b37458SLiu Junliang if (!is_valid_ether_addr(addr->sa_data)) { 294c9b37458SLiu Junliang netdev_err(netdev, "not setting invalid mac address %pM\n", 295c9b37458SLiu Junliang addr->sa_data); 296c9b37458SLiu Junliang return -EINVAL; 297c9b37458SLiu Junliang } 298c9b37458SLiu Junliang 299c9b37458SLiu Junliang memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); 300*06b19b1bSChen Gang sr_write_async(dev, SR_PAR, 6, netdev->dev_addr); 301c9b37458SLiu Junliang 302c9b37458SLiu Junliang return 0; 303c9b37458SLiu Junliang } 304c9b37458SLiu Junliang 305c9b37458SLiu Junliang static const struct net_device_ops sr9700_netdev_ops = { 306c9b37458SLiu Junliang .ndo_open = usbnet_open, 307c9b37458SLiu Junliang .ndo_stop = usbnet_stop, 308c9b37458SLiu Junliang .ndo_start_xmit = usbnet_start_xmit, 309c9b37458SLiu Junliang .ndo_tx_timeout = usbnet_tx_timeout, 310c9b37458SLiu Junliang .ndo_change_mtu = usbnet_change_mtu, 311c9b37458SLiu Junliang .ndo_validate_addr = eth_validate_addr, 312c9b37458SLiu Junliang .ndo_do_ioctl = sr9700_ioctl, 313c9b37458SLiu Junliang .ndo_set_rx_mode = sr9700_set_multicast, 314c9b37458SLiu Junliang .ndo_set_mac_address = sr9700_set_mac_address, 315c9b37458SLiu Junliang }; 316c9b37458SLiu Junliang 317c9b37458SLiu Junliang static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf) 318c9b37458SLiu Junliang { 319c9b37458SLiu Junliang struct net_device *netdev; 320c9b37458SLiu Junliang struct mii_if_info *mii; 321c9b37458SLiu Junliang int ret; 322c9b37458SLiu Junliang 323c9b37458SLiu Junliang ret = usbnet_get_endpoints(dev, intf); 324c9b37458SLiu Junliang if (ret) 325c9b37458SLiu Junliang goto out; 326c9b37458SLiu Junliang 327c9b37458SLiu Junliang netdev = dev->net; 328c9b37458SLiu Junliang 329c9b37458SLiu Junliang netdev->netdev_ops = &sr9700_netdev_ops; 330c9b37458SLiu Junliang netdev->ethtool_ops = &sr9700_ethtool_ops; 331c9b37458SLiu Junliang netdev->hard_header_len += SR_TX_OVERHEAD; 332c9b37458SLiu Junliang dev->hard_mtu = netdev->mtu + netdev->hard_header_len; 333c9b37458SLiu Junliang /* bulkin buffer is preferably not less than 3K */ 334c9b37458SLiu Junliang dev->rx_urb_size = 3072; 335c9b37458SLiu Junliang 336c9b37458SLiu Junliang mii = &dev->mii; 337c9b37458SLiu Junliang mii->dev = netdev; 338c9b37458SLiu Junliang mii->mdio_read = sr_mdio_read; 339c9b37458SLiu Junliang mii->mdio_write = sr_mdio_write; 340c9b37458SLiu Junliang mii->phy_id_mask = 0x1f; 341c9b37458SLiu Junliang mii->reg_num_mask = 0x1f; 342c9b37458SLiu Junliang 343*06b19b1bSChen Gang sr_write_reg(dev, SR_NCR, NCR_RST); 344c9b37458SLiu Junliang udelay(20); 345c9b37458SLiu Junliang 346c9b37458SLiu Junliang /* read MAC 347c9b37458SLiu Junliang * After Chip Power on, the Chip will reload the MAC from 348c9b37458SLiu Junliang * EEPROM automatically to PAR. In case there is no EEPROM externally, 349c9b37458SLiu Junliang * a default MAC address is stored in PAR for making chip work properly. 350c9b37458SLiu Junliang */ 351*06b19b1bSChen Gang if (sr_read(dev, SR_PAR, ETH_ALEN, netdev->dev_addr) < 0) { 352c9b37458SLiu Junliang netdev_err(netdev, "Error reading MAC address\n"); 353c9b37458SLiu Junliang ret = -ENODEV; 354c9b37458SLiu Junliang goto out; 355c9b37458SLiu Junliang } 356c9b37458SLiu Junliang 357c9b37458SLiu Junliang /* power up and reset phy */ 358*06b19b1bSChen Gang sr_write_reg(dev, SR_PRR, PRR_PHY_RST); 359c9b37458SLiu Junliang /* at least 10ms, here 20ms for safe */ 360c9b37458SLiu Junliang mdelay(20); 361*06b19b1bSChen Gang sr_write_reg(dev, SR_PRR, 0); 362c9b37458SLiu Junliang /* at least 1ms, here 2ms for reading right register */ 363c9b37458SLiu Junliang udelay(2 * 1000); 364c9b37458SLiu Junliang 365c9b37458SLiu Junliang /* receive broadcast packets */ 366c9b37458SLiu Junliang sr9700_set_multicast(netdev); 367c9b37458SLiu Junliang 368c9b37458SLiu Junliang sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET); 369c9b37458SLiu Junliang sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL | 370c9b37458SLiu Junliang ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 371c9b37458SLiu Junliang mii_nway_restart(mii); 372c9b37458SLiu Junliang 373c9b37458SLiu Junliang out: 374c9b37458SLiu Junliang return ret; 375c9b37458SLiu Junliang } 376c9b37458SLiu Junliang 377c9b37458SLiu Junliang static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 378c9b37458SLiu Junliang { 379c9b37458SLiu Junliang struct sk_buff *sr_skb; 380c9b37458SLiu Junliang int len; 381c9b37458SLiu Junliang 382c9b37458SLiu Junliang /* skb content (packets) format : 383c9b37458SLiu Junliang * p0 p1 p2 ...... pm 384c9b37458SLiu Junliang * / \ 385c9b37458SLiu Junliang * / \ 386c9b37458SLiu Junliang * / \ 387c9b37458SLiu Junliang * / \ 388c9b37458SLiu Junliang * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn 389c9b37458SLiu Junliang * 390c9b37458SLiu Junliang * p0 : packet 0 391c9b37458SLiu Junliang * p0b0 : packet 0 byte 0 392c9b37458SLiu Junliang * 393c9b37458SLiu Junliang * b0: rx status 394c9b37458SLiu Junliang * b1: packet length (incl crc) low 395c9b37458SLiu Junliang * b2: packet length (incl crc) high 396c9b37458SLiu Junliang * b3..n-4: packet data 397c9b37458SLiu Junliang * bn-3..bn: ethernet packet crc 398c9b37458SLiu Junliang */ 399c9b37458SLiu Junliang if (unlikely(skb->len < SR_RX_OVERHEAD)) { 400c9b37458SLiu Junliang netdev_err(dev->net, "unexpected tiny rx frame\n"); 401c9b37458SLiu Junliang return 0; 402c9b37458SLiu Junliang } 403c9b37458SLiu Junliang 404c9b37458SLiu Junliang /* one skb may contains multiple packets */ 405c9b37458SLiu Junliang while (skb->len > SR_RX_OVERHEAD) { 406c9b37458SLiu Junliang if (skb->data[0] != 0x40) 407c9b37458SLiu Junliang return 0; 408c9b37458SLiu Junliang 409c9b37458SLiu Junliang /* ignore the CRC length */ 410c9b37458SLiu Junliang len = (skb->data[1] | (skb->data[2] << 8)) - 4; 411c9b37458SLiu Junliang 412c9b37458SLiu Junliang if (len > ETH_FRAME_LEN) 413c9b37458SLiu Junliang return 0; 414c9b37458SLiu Junliang 415c9b37458SLiu Junliang /* the last packet of current skb */ 416c9b37458SLiu Junliang if (skb->len == (len + SR_RX_OVERHEAD)) { 417c9b37458SLiu Junliang skb_pull(skb, 3); 418c9b37458SLiu Junliang skb->len = len; 419c9b37458SLiu Junliang skb_set_tail_pointer(skb, len); 420c9b37458SLiu Junliang skb->truesize = len + sizeof(struct sk_buff); 421c9b37458SLiu Junliang return 2; 422c9b37458SLiu Junliang } 423c9b37458SLiu Junliang 424c9b37458SLiu Junliang /* skb_clone is used for address align */ 425c9b37458SLiu Junliang sr_skb = skb_clone(skb, GFP_ATOMIC); 426c9b37458SLiu Junliang if (!sr_skb) 427c9b37458SLiu Junliang return 0; 428c9b37458SLiu Junliang 429c9b37458SLiu Junliang sr_skb->len = len; 430c9b37458SLiu Junliang sr_skb->data = skb->data + 3; 431c9b37458SLiu Junliang skb_set_tail_pointer(sr_skb, len); 432c9b37458SLiu Junliang sr_skb->truesize = len + sizeof(struct sk_buff); 433c9b37458SLiu Junliang usbnet_skb_return(dev, sr_skb); 434c9b37458SLiu Junliang 435c9b37458SLiu Junliang skb_pull(skb, len + SR_RX_OVERHEAD); 436c9b37458SLiu Junliang }; 437c9b37458SLiu Junliang 438c9b37458SLiu Junliang return 0; 439c9b37458SLiu Junliang } 440c9b37458SLiu Junliang 441c9b37458SLiu Junliang static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 442c9b37458SLiu Junliang gfp_t flags) 443c9b37458SLiu Junliang { 444c9b37458SLiu Junliang int len; 445c9b37458SLiu Junliang 446c9b37458SLiu Junliang /* SR9700 can only send out one ethernet packet at once. 447c9b37458SLiu Junliang * 448c9b37458SLiu Junliang * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn 449c9b37458SLiu Junliang * 450c9b37458SLiu Junliang * b0: rx status 451c9b37458SLiu Junliang * b1: packet length (incl crc) low 452c9b37458SLiu Junliang * b2: packet length (incl crc) high 453c9b37458SLiu Junliang * b3..n-4: packet data 454c9b37458SLiu Junliang * bn-3..bn: ethernet packet crc 455c9b37458SLiu Junliang */ 456c9b37458SLiu Junliang 457c9b37458SLiu Junliang len = skb->len; 458c9b37458SLiu Junliang 459c9b37458SLiu Junliang if (skb_headroom(skb) < SR_TX_OVERHEAD) { 460c9b37458SLiu Junliang struct sk_buff *skb2; 461c9b37458SLiu Junliang 462c9b37458SLiu Junliang skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags); 463c9b37458SLiu Junliang dev_kfree_skb_any(skb); 464c9b37458SLiu Junliang skb = skb2; 465c9b37458SLiu Junliang if (!skb) 466c9b37458SLiu Junliang return NULL; 467c9b37458SLiu Junliang } 468c9b37458SLiu Junliang 469c9b37458SLiu Junliang __skb_push(skb, SR_TX_OVERHEAD); 470c9b37458SLiu Junliang 471c9b37458SLiu Junliang /* usbnet adds padding if length is a multiple of packet size 472c9b37458SLiu Junliang * if so, adjust length value in header 473c9b37458SLiu Junliang */ 474c9b37458SLiu Junliang if ((skb->len % dev->maxpacket) == 0) 475c9b37458SLiu Junliang len++; 476c9b37458SLiu Junliang 477c9b37458SLiu Junliang skb->data[0] = len; 478c9b37458SLiu Junliang skb->data[1] = len >> 8; 479c9b37458SLiu Junliang 480c9b37458SLiu Junliang return skb; 481c9b37458SLiu Junliang } 482c9b37458SLiu Junliang 483c9b37458SLiu Junliang static void sr9700_status(struct usbnet *dev, struct urb *urb) 484c9b37458SLiu Junliang { 485c9b37458SLiu Junliang int link; 486c9b37458SLiu Junliang u8 *buf; 487c9b37458SLiu Junliang 488c9b37458SLiu Junliang /* format: 489c9b37458SLiu Junliang b0: net status 490c9b37458SLiu Junliang b1: tx status 1 491c9b37458SLiu Junliang b2: tx status 2 492c9b37458SLiu Junliang b3: rx status 493c9b37458SLiu Junliang b4: rx overflow 494c9b37458SLiu Junliang b5: rx count 495c9b37458SLiu Junliang b6: tx count 496c9b37458SLiu Junliang b7: gpr 497c9b37458SLiu Junliang */ 498c9b37458SLiu Junliang 499c9b37458SLiu Junliang if (urb->actual_length < 8) 500c9b37458SLiu Junliang return; 501c9b37458SLiu Junliang 502c9b37458SLiu Junliang buf = urb->transfer_buffer; 503c9b37458SLiu Junliang 504c9b37458SLiu Junliang link = !!(buf[0] & 0x40); 505c9b37458SLiu Junliang if (netif_carrier_ok(dev->net) != link) { 506c9b37458SLiu Junliang usbnet_link_change(dev, link, 1); 507c9b37458SLiu Junliang netdev_dbg(dev->net, "Link Status is: %d\n", link); 508c9b37458SLiu Junliang } 509c9b37458SLiu Junliang } 510c9b37458SLiu Junliang 511c9b37458SLiu Junliang static int sr9700_link_reset(struct usbnet *dev) 512c9b37458SLiu Junliang { 513c9b37458SLiu Junliang struct ethtool_cmd ecmd; 514c9b37458SLiu Junliang 515c9b37458SLiu Junliang mii_check_media(&dev->mii, 1, 1); 516c9b37458SLiu Junliang mii_ethtool_gset(&dev->mii, &ecmd); 517c9b37458SLiu Junliang 518c9b37458SLiu Junliang netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", 519c9b37458SLiu Junliang ecmd.speed, ecmd.duplex); 520c9b37458SLiu Junliang 521c9b37458SLiu Junliang return 0; 522c9b37458SLiu Junliang } 523c9b37458SLiu Junliang 524c9b37458SLiu Junliang static const struct driver_info sr9700_driver_info = { 525c9b37458SLiu Junliang .description = "CoreChip SR9700 USB Ethernet", 526c9b37458SLiu Junliang .flags = FLAG_ETHER, 527c9b37458SLiu Junliang .bind = sr9700_bind, 528c9b37458SLiu Junliang .rx_fixup = sr9700_rx_fixup, 529c9b37458SLiu Junliang .tx_fixup = sr9700_tx_fixup, 530c9b37458SLiu Junliang .status = sr9700_status, 531c9b37458SLiu Junliang .link_reset = sr9700_link_reset, 532c9b37458SLiu Junliang .reset = sr9700_link_reset, 533c9b37458SLiu Junliang }; 534c9b37458SLiu Junliang 535c9b37458SLiu Junliang static const struct usb_device_id products[] = { 536c9b37458SLiu Junliang { 537c9b37458SLiu Junliang USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */ 538c9b37458SLiu Junliang .driver_info = (unsigned long)&sr9700_driver_info, 539c9b37458SLiu Junliang }, 540c9b37458SLiu Junliang {}, /* END */ 541c9b37458SLiu Junliang }; 542c9b37458SLiu Junliang 543c9b37458SLiu Junliang MODULE_DEVICE_TABLE(usb, products); 544c9b37458SLiu Junliang 545c9b37458SLiu Junliang static struct usb_driver sr9700_usb_driver = { 546c9b37458SLiu Junliang .name = "sr9700", 547c9b37458SLiu Junliang .id_table = products, 548c9b37458SLiu Junliang .probe = usbnet_probe, 549c9b37458SLiu Junliang .disconnect = usbnet_disconnect, 550c9b37458SLiu Junliang .suspend = usbnet_suspend, 551c9b37458SLiu Junliang .resume = usbnet_resume, 552c9b37458SLiu Junliang .disable_hub_initiated_lpm = 1, 553c9b37458SLiu Junliang }; 554c9b37458SLiu Junliang 555c9b37458SLiu Junliang module_usb_driver(sr9700_usb_driver); 556c9b37458SLiu Junliang 557c9b37458SLiu Junliang MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>"); 558c9b37458SLiu Junliang MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/"); 559c9b37458SLiu Junliang MODULE_LICENSE("GPL"); 560