⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asix.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	__le16 v;	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);	if (ret < 0) {		deverr(dev, "Error reading Medium Status register: %02x", ret);		goto out;	}	ret = le16_to_cpu(v);out:	return ret;}static int asix_write_medium_mode(struct usbnet *dev, u16 mode){	int ret;	devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode);	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);	if (ret < 0)		deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x",			mode, ret);	return ret;}static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep){	int ret;	devdbg(dev,"asix_write_gpio() - value = 0x%04x", value);	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);	if (ret < 0)		deverr(dev, "Failed to write GPIO value 0x%04x: %02x",			value, ret);	if (sleep)		msleep(sleep);	return ret;}/* * AX88772 & AX88178 have a 16-bit RX_CTL value */static void asix_set_multicast(struct net_device *net){	struct usbnet *dev = netdev_priv(net);	struct asix_data *data = (struct asix_data *)&dev->data;	u16 rx_ctl = AX_DEFAULT_RX_CTL;	if (net->flags & IFF_PROMISC) {		rx_ctl |= AX_RX_CTL_PRO;	} else if (net->flags & IFF_ALLMULTI		   || net->mc_count > AX_MAX_MCAST) {		rx_ctl |= AX_RX_CTL_AMALL;	} 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;		}		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,				   AX_MCAST_FILTER_SIZE, data->multi_filter);		rx_ctl |= AX_RX_CTL_AM;	}	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);}static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc){	struct usbnet *dev = netdev_priv(netdev);	__le16 res;	mutex_lock(&dev->phy_mutex);	asix_set_sw_mii(dev);	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,				(__u16)loc, 2, &res);	asix_set_hw_mii(dev);	mutex_unlock(&dev->phy_mutex);	devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res));	return le16_to_cpu(res);}static voidasix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val){	struct usbnet *dev = netdev_priv(netdev);	__le16 res = cpu_to_le16(val);	devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);	mutex_lock(&dev->phy_mutex);	asix_set_sw_mii(dev);	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);	asix_set_hw_mii(dev);	mutex_unlock(&dev->phy_mutex);}/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */static u32 asix_get_phyid(struct usbnet *dev){	int phy_reg;	u32 phy_id;	phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);	if (phy_reg < 0)		return 0;	phy_id = (phy_reg & 0xffff) << 16;	phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);	if (phy_reg < 0)		return 0;	phy_id |= (phy_reg & 0xffff);	return phy_id;}static voidasix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo){	struct usbnet *dev = netdev_priv(net);	u8 opt;	if (asix_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 intasix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo){	struct usbnet *dev = netdev_priv(net);	u8 opt = 0;	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 (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,			      opt, 0, 0, NULL) < 0)		return -EINVAL;	return 0;}static int asix_get_eeprom_len(struct net_device *net){	struct usbnet *dev = netdev_priv(net);	struct asix_data *data = (struct asix_data *)&dev->data;	return data->eeprom_len;}static int asix_get_eeprom(struct net_device *net,			      struct ethtool_eeprom *eeprom, u8 *data){	struct usbnet *dev = netdev_priv(net);	__le16 *ebuf = (__le16 *)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;	eeprom->magic = AX_EEPROM_MAGIC;	/* ax8817x returns 2 bytes from eeprom on read */	for (i=0; i < eeprom->len / 2; i++) {		if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,			eeprom->offset + i, 0, 2, &ebuf[i]) < 0)			return -EINVAL;	}	return 0;}static void asix_get_drvinfo (struct net_device *net,				 struct ethtool_drvinfo *info){	struct usbnet *dev = netdev_priv(net);	struct asix_data *data = (struct asix_data *)&dev->data;	/* Inherit standard device info */	usbnet_get_drvinfo(net, info);	strncpy (info->driver, driver_name, sizeof info->driver);	strncpy (info->version, DRIVER_VERSION, sizeof info->version);	info->eedump_len = data->eeprom_len;}static u32 asix_get_link(struct net_device *net){	struct usbnet *dev = netdev_priv(net);	return mii_link_ok(&dev->mii);}static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd){	struct usbnet *dev = netdev_priv(net);	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);}/* 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 ax88172_ethtool_ops = {	.get_drvinfo		= asix_get_drvinfo,	.get_link		= asix_get_link,	.get_msglevel		= usbnet_get_msglevel,	.set_msglevel		= usbnet_set_msglevel,	.get_wol		= asix_get_wol,	.set_wol		= asix_set_wol,	.get_eeprom_len		= asix_get_eeprom_len,	.get_eeprom		= asix_get_eeprom,	.get_settings		= usbnet_get_settings,	.set_settings		= usbnet_set_settings,	.nway_reset		= usbnet_nway_reset,};static void ax88172_set_multicast(struct net_device *net){	struct usbnet *dev = netdev_priv(net);	struct asix_data *data = (struct asix_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;		}		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,				   AX_MCAST_FILTER_SIZE, data->multi_filter);		rx_ctl |= 0x10;	}	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);}static int ax88172_link_reset(struct usbnet *dev){	u8 mode;	struct ethtool_cmd ecmd;	mii_check_media(&dev->mii, 1, 1);	mii_ethtool_gset(&dev->mii, &ecmd);	mode = AX88172_MEDIUM_DEFAULT;	if (ecmd.duplex != DUPLEX_FULL)		mode |= ~AX88172_MEDIUM_FD;	devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);	asix_write_medium_mode(dev, mode);	return 0;}static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf){	int ret = 0;	u8 buf[ETH_ALEN];	int i;	unsigned long gpio_bits = dev->driver_info->data;	struct asix_data *data = (struct asix_data *)&dev->data;	data->eeprom_len = AX88172_EEPROM_LEN;	usbnet_get_endpoints(dev,intf);	/* Toggle the GPIOs in a manufacturer/model specific way */	for (i = 2; i >= 0; i--) {		if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,					(gpio_bits >> (i * 8)) & 0xff, 0, 0,					NULL)) < 0)			goto out;		msleep(5);	}	if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)		goto out;	/* Get the MAC address */	if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,				0, 0, ETH_ALEN, buf)) < 0) {		dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);		goto out;	}	memcpy(dev->net->dev_addr, buf, ETH_ALEN);	/* Initialize MII structure */	dev->mii.dev = dev->net;	dev->mii.mdio_read = asix_mdio_read;	dev->mii.mdio_write = asix_mdio_write;	dev->mii.phy_id_mask = 0x3f;	dev->mii.reg_num_mask = 0x1f;	dev->mii.phy_id = asix_get_phy_addr(dev);	dev->net->do_ioctl = asix_ioctl;	dev->net->set_multicast_list = ax88172_set_multicast;	dev->net->ethtool_ops = &ax88172_ethtool_ops;	asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);	asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,		ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);	mii_nway_restart(&dev->mii);	return 0;out:	return ret;}static struct ethtool_ops ax88772_ethtool_ops = {	.get_drvinfo		= asix_get_drvinfo,	.get_link		= asix_get_link,	.get_msglevel		= usbnet_get_msglevel,	.set_msglevel		= usbnet_set_msglevel,	.get_wol		= asix_get_wol,	.set_wol		= asix_set_wol,	.get_eeprom_len		= asix_get_eeprom_len,	.get_eeprom		= asix_get_eeprom,	.get_settings		= usbnet_get_settings,	.set_settings		= usbnet_set_settings,	.nway_reset		= usbnet_nway_reset,};static int ax88772_link_reset(struct usbnet *dev){	u16 mode;	struct ethtool_cmd ecmd;	mii_check_media(&dev->mii, 1, 1);	mii_ethtool_gset(&dev->mii, &ecmd);	mode = AX88772_MEDIUM_DEFAULT;	if (ecmd.speed != SPEED_100)		mode &= ~AX_MEDIUM_PS;	if (ecmd.duplex != DUPLEX_FULL)		mode &= ~AX_MEDIUM_FD;	devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);	asix_write_medium_mode(dev, mode);	return 0;}static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf){	int ret, embd_phy;	u16 rx_ctl;	struct asix_data *data = (struct asix_data *)&dev->data;	u8 buf[ETH_ALEN];	u32 phyid;	data->eeprom_len = AX88772_EEPROM_LEN;	usbnet_get_endpoints(dev,intf);	if ((ret = asix_write_gpio(dev,			AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)		goto out;	/* 0x10 is the phy id of the embedded 10/100 ethernet phy */	embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);	if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,				embd_phy, 0, 0, NULL)) < 0) {		dbg("Select PHY #1 failed: %d", ret);		goto out;	}	if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0)		goto out;	msleep(150);	if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0)		goto out;	msleep(150);	if (embd_phy) {		if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0)			goto out;	}	else {		if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0)			goto out;	}	msleep(150);	rx_ctl = asix_read_rx_ctl(dev);	dbg("RX_CTL is 0x%04x after software reset", rx_ctl);	if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)		goto out;	rx_ctl = asix_read_rx_ctl(dev);	dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);	/* Get the MAC address */	if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,				0, 0, ETH_ALEN, buf)) < 0) {		dbg("Failed to read MAC address: %d", ret);		goto out;	}	memcpy(dev->net->dev_addr, buf, ETH_ALEN);	/* Initialize MII structure */	dev->mii.dev = dev->net;	dev->mii.mdio_read = asix_mdio_read;	dev->mii.mdio_write = asix_mdio_write;	dev->mii.phy_id_mask = 0x1f;	dev->mii.reg_num_mask = 0x1f;	dev->net->do_ioctl = asix_ioctl;	dev->mii.phy_id = asix_get_phy_addr(dev);	phyid = asix_get_phyid(dev);	dbg("PHYID=0x%08x", phyid);	if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)		goto out;	msleep(150);	if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0)		goto out;	msleep(150);	dev->net->set_multicast_list = asix_set_multicast;	dev->net->ethtool_ops = &ax88772_ethtool_ops;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -