drivers/net/usb/asix_devices.c

Source file repositories/reference/linux-study-clean/drivers/net/usb/asix_devices.c

File Facts

System
Linux kernel
Corpus path
drivers/net/usb/asix_devices.c
Extension
.c
Size
43129 bytes
Lines
1635
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops ax88172_netdev_ops = {
	.ndo_open		= usbnet_open,
	.ndo_stop		= usbnet_stop,
	.ndo_start_xmit		= usbnet_start_xmit,
	.ndo_tx_timeout		= usbnet_tx_timeout,
	.ndo_change_mtu		= usbnet_change_mtu,
	.ndo_get_stats64	= dev_get_tstats64,
	.ndo_set_mac_address 	= eth_mac_addr,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_eth_ioctl		= usbnet_mii_ioctl,
	.ndo_set_rx_mode	= ax88172_set_multicast,
};

static void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits)
{
	unsigned int timeout = 5000;

	asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, reset_bits);

	/* give phy_id a chance to process reset */
	udelay(500);

	/* See IEEE 802.3 "22.2.4.1.1 Reset": 500ms max */
	while (timeout--) {
		if (asix_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR)
							& BMCR_RESET)
			udelay(100);
		else
			return;
	}

	netdev_err(dev->net, "BMCR_RESET timeout on phy_id %d\n",
		   dev->mii.phy_id);
}

static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
{
	int ret = 0;
	u8 buf[ETH_ALEN] = {0};
	int i;
	unsigned long gpio_bits = dev->driver_info->data;

	ret = usbnet_get_endpoints(dev, intf);
	if (ret)
		goto out;

	/* Toggle the GPIOs in a manufacturer/model specific way */
	for (i = 2; i >= 0; i--) {
		ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
				(gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL, 0);
		if (ret < 0)
			goto out;
		msleep(5);
	}

	ret = asix_write_rx_ctl(dev, 0x80, 0);
	if (ret < 0)
		goto out;

	/* Get the MAC address */
	ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
			    0, 0, ETH_ALEN, buf, 0);
	if (ret < 0) {
		netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n",
			   ret);
		goto out;
	}

	asix_set_netdev_dev_addr(dev, buf);

	/* 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_read_phy_addr(dev, true);
	if (dev->mii.phy_id < 0)
		return dev->mii.phy_id;

	dev->net->netdev_ops = &ax88172_netdev_ops;
	dev->net->ethtool_ops = &ax88172_ethtool_ops;
	dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */
	dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */

	asix_phy_reset(dev, 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);

Annotation

Implementation Notes