drivers/net/ethernet/microchip/enc28j60.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/microchip/enc28j60.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/microchip/enc28j60.c
Extension
.c
Size
45062 bytes
Lines
1630
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 enc28j60_netdev_ops = {
	.ndo_open		= enc28j60_net_open,
	.ndo_stop		= enc28j60_net_close,
	.ndo_start_xmit		= enc28j60_send_packet,
	.ndo_set_rx_mode	= enc28j60_set_multicast_list,
	.ndo_set_mac_address	= enc28j60_set_mac_address,
	.ndo_tx_timeout		= enc28j60_tx_timeout,
	.ndo_validate_addr	= eth_validate_addr,
};

static int enc28j60_probe(struct spi_device *spi)
{
	struct net_device *dev;
	struct enc28j60_net *priv;
	int ret = 0;

	if (netif_msg_drv(&debug))
		dev_info(&spi->dev, "Ethernet driver %s loaded\n", DRV_VERSION);

	dev = alloc_etherdev(sizeof(struct enc28j60_net));
	if (!dev) {
		ret = -ENOMEM;
		goto error_alloc;
	}
	priv = netdev_priv(dev);

	priv->netdev = dev;	/* priv to netdev reference */
	priv->spi = spi;	/* priv to spi reference */
	priv->msg_enable = netif_msg_init(debug.msg_enable, ENC28J60_MSG_DEFAULT);
	mutex_init(&priv->lock);
	INIT_WORK(&priv->tx_work, enc28j60_tx_work_handler);
	INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler);
	INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler);
	spi_set_drvdata(spi, priv);	/* spi to priv reference */
	SET_NETDEV_DEV(dev, &spi->dev);

	if (!enc28j60_chipset_init(dev)) {
		if (netif_msg_probe(priv))
			dev_info(&spi->dev, "chip not found\n");
		ret = -EIO;
		goto error_irq;
	}

	if (device_get_ethdev_address(&spi->dev, dev))
		eth_hw_addr_random(dev);
	enc28j60_set_hw_macaddr(dev);

	/* Board setup must set the relevant edge trigger type;
	 * level triggers won't currently work.
	 */
	ret = request_threaded_irq(spi->irq, NULL, enc28j60_irq, IRQF_ONESHOT,
				   DRV_NAME, priv);
	if (ret < 0) {
		if (netif_msg_probe(priv))
			dev_err(&spi->dev, "request irq %d failed (ret = %d)\n",
				spi->irq, ret);
		goto error_irq;
	}

	dev->if_port = IF_PORT_10BASET;
	dev->irq = spi->irq;
	dev->netdev_ops = &enc28j60_netdev_ops;
	dev->watchdog_timeo = TX_TIMEOUT;
	dev->ethtool_ops = &enc28j60_ethtool_ops;

	enc28j60_lowpower(priv, true);

	ret = register_netdev(dev);
	if (ret) {
		if (netif_msg_probe(priv))
			dev_err(&spi->dev, "register netdev failed (ret = %d)\n",
				ret);
		goto error_register;
	}

	return 0;

error_register:
	free_irq(spi->irq, priv);
error_irq:
	free_netdev(dev);
error_alloc:
	return ret;
}

static void enc28j60_remove(struct spi_device *spi)
{
	struct enc28j60_net *priv = spi_get_drvdata(spi);

	unregister_netdev(priv->netdev);

Annotation

Implementation Notes