drivers/net/usb/smsc95xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/usb/smsc95xx.c
Extension
.c
Size
54430 bytes
Lines
2196
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 smsc95xx_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		= phy_do_ioctl_running,
	.ndo_set_rx_mode	= smsc95xx_set_multicast,
	.ndo_set_features	= smsc95xx_set_features,
};

static void smsc95xx_handle_link_change(struct net_device *net)
{
	struct usbnet *dev = netdev_priv(net);

	phy_print_status(net->phydev);
	smsc95xx_mac_update_fullduplex(dev);
	usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
}

static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
{
	struct smsc95xx_priv *pdata;
	char usb_path[64];
	int ret, phy_irq;
	u32 val;

	ret = usbnet_get_endpoints(dev, intf);
	if (ret < 0) {
		netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
		return ret;
	}

	pdata = kzalloc_obj(*pdata);
	if (!pdata)
		return -ENOMEM;

	dev->driver_priv = pdata;

	spin_lock_init(&pdata->mac_cr_lock);

	/* LAN95xx devices do not alter the computed checksum of 0 to 0xffff.
	 * RFC 2460, ipv6 UDP calculated checksum yields a result of zero must
	 * be changed to 0xffff. RFC 768, ipv4 UDP computed checksum is zero,
	 * it is transmitted as all ones. The zero transmitted checksum means
	 * transmitter generated no checksum. Hence, enable csum offload only
	 * for ipv4 packets.
	 */
	if (DEFAULT_TX_CSUM_ENABLE)
		dev->net->features |= NETIF_F_IP_CSUM;
	if (DEFAULT_RX_CSUM_ENABLE)
		dev->net->features |= NETIF_F_RXCSUM;

	dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
	set_bit(EVENT_NO_IP_ALIGN, &dev->flags);

	smsc95xx_init_mac_address(dev);

	/* Init all registers */
	ret = smsc95xx_reset(dev);
	if (ret)
		goto free_pdata;

	/* create irq domain for use by PHY driver and GPIO consumers */
	usb_make_path(dev->udev, usb_path, sizeof(usb_path));
	pdata->irqfwnode = irq_domain_alloc_named_fwnode(usb_path);
	if (!pdata->irqfwnode) {
		ret = -ENOMEM;
		goto free_pdata;
	}

	pdata->irqdomain = irq_domain_create_linear(pdata->irqfwnode,
						    SMSC95XX_NR_IRQS,
						    &irq_domain_simple_ops,
						    pdata);
	if (!pdata->irqdomain) {
		ret = -ENOMEM;
		goto free_irqfwnode;
	}

	phy_irq = irq_create_mapping(pdata->irqdomain, PHY_HWIRQ);
	if (!phy_irq) {
		ret = -ENOENT;
		goto remove_irqdomain;
	}

	pdata->irqchip = dummy_irq_chip;

Annotation

Implementation Notes