drivers/net/ethernet/3com/3c509.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/3com/3c509.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/3com/3c509.c
Extension
.c
Size
39966 bytes
Lines
1544
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 netdev_ops = {
	.ndo_open		= el3_open,
	.ndo_stop		= el3_close,
	.ndo_start_xmit		= el3_start_xmit,
	.ndo_get_stats		= el3_get_stats,
	.ndo_set_rx_mode	= set_multicast_list,
	.ndo_tx_timeout		= el3_tx_timeout,
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_validate_addr	= eth_validate_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= el3_poll_controller,
#endif
};

static int el3_common_init(struct net_device *dev)
{
	static const char *const if_names[] = {
		"10baseT", "AUI", "undefined", "BNC"
	};
	struct el3_private *lp = netdev_priv(dev);
	int err;

	spin_lock_init(&lp->lock);

	if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */
		dev->if_port = (dev->mem_start & 0x0f);
	} else { /* xcvr codes 0/8 */
		/* use eeprom value, but save user's full-duplex selection */
		dev->if_port |= (dev->mem_start & 0x08);
	}

	/* The EL3-specific entries in the device structure. */
	dev->netdev_ops = &netdev_ops;
	dev->watchdog_timeo = TX_TIMEOUT;
	dev->ethtool_ops = &ethtool_ops;

	err = register_netdev(dev);
	if (err) {
		pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n",
		       dev->base_addr, dev->irq);
		release_region(dev->base_addr, EL3_IO_EXTENT);
		return err;
	}

	pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n",
		dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
		dev->dev_addr, dev->irq);

	return 0;
}

static void el3_common_remove(struct net_device *dev)
{
	unregister_netdev(dev);
	release_region(dev->base_addr, EL3_IO_EXTENT);
	free_netdev(dev);
}

#ifdef CONFIG_EISA
static int el3_eisa_probe(struct device *device)
{
	struct net_device *dev = NULL;
	struct eisa_device *edev;
	int ioaddr, irq, if_port;
	__be16 phys_addr[3];
	short i;
	int err;

	/* Yeepee, The driver framework is calling us ! */
	edev = to_eisa_device(device);
	ioaddr = edev->base_addr;

	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))
		return -EBUSY;

	/* Change the register set to the configuration window 0. */
	outw(SELECT_WINDOW | 0, ioaddr + 0xC80 + EL3_CMD);

	irq = inw(ioaddr + WN0_IRQ) >> 12;
	if_port = inw(ioaddr + 6) >> 14;
	for (i = 0; i < 3; i++)
		phys_addr[i] = htons(read_eeprom(ioaddr, i));

	/* Restore the "Product ID" to the EEPROM read register. */
	read_eeprom(ioaddr, 3);

	dev = alloc_etherdev(sizeof(struct el3_private));
	if (!dev) {
		release_region(ioaddr, EL3_IO_EXTENT);
		return -ENOMEM;

Annotation

Implementation Notes