drivers/net/usb/smsc75xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/usb/smsc75xx.c
Extension
.c
Size
58031 bytes
Lines
2340
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 smsc75xx_netdev_ops = {
	.ndo_open		= usbnet_open,
	.ndo_stop		= usbnet_stop,
	.ndo_start_xmit		= usbnet_start_xmit,
	.ndo_tx_timeout		= usbnet_tx_timeout,
	.ndo_get_stats64	= dev_get_tstats64,
	.ndo_change_mtu		= smsc75xx_change_mtu,
	.ndo_set_mac_address 	= eth_mac_addr,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_eth_ioctl		= smsc75xx_ioctl,
	.ndo_set_rx_mode	= smsc75xx_set_multicast,
	.ndo_set_features	= smsc75xx_set_features,
};

static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
{
	struct smsc75xx_priv *pdata = NULL;
	int ret;

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

	dev->data[0] = (unsigned long) kzalloc_obj(struct smsc75xx_priv);

	pdata = (struct smsc75xx_priv *)(dev->data[0]);
	if (!pdata)
		return -ENOMEM;

	pdata->dev = dev;

	spin_lock_init(&pdata->rfe_ctl_lock);
	mutex_init(&pdata->dataport_mutex);

	INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);

	if (DEFAULT_TX_CSUM_ENABLE)
		dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;

	if (DEFAULT_RX_CSUM_ENABLE)
		dev->net->features |= NETIF_F_RXCSUM;

	dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
				NETIF_F_RXCSUM;

	ret = smsc75xx_wait_ready(dev, 0);
	if (ret < 0) {
		netdev_warn(dev->net, "device not ready in smsc75xx_bind\n");
		goto free_pdata;
	}

	smsc75xx_init_mac_address(dev);

	/* Init all registers */
	ret = smsc75xx_reset(dev);
	if (ret < 0) {
		netdev_warn(dev->net, "smsc75xx_reset error %d\n", ret);
		goto cancel_work;
	}

	dev->net->netdev_ops = &smsc75xx_netdev_ops;
	dev->net->ethtool_ops = &smsc75xx_ethtool_ops;
	dev->net->flags |= IFF_MULTICAST;
	dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD;
	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
	dev->net->max_mtu = MAX_SINGLE_PACKET_SIZE;
	return 0;

cancel_work:
	cancel_work_sync(&pdata->set_multicast);
free_pdata:
	kfree(pdata);
	dev->data[0] = 0;
	return ret;
}

static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
{
	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
	if (pdata) {
		cancel_work_sync(&pdata->set_multicast);
		netif_dbg(dev, ifdown, dev->net, "free pdata\n");
		kfree(pdata);
		dev->data[0] = 0;
	}
}

static u16 smsc_crc(const u8 *buffer, size_t len)

Annotation

Implementation Notes