drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c

Source file repositories/reference/linux-study-clean/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
Extension
.c
Size
30767 bytes
Lines
1056
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 kvaser_usb_netdev_ops = {
	.ndo_open = kvaser_usb_open,
	.ndo_stop = kvaser_usb_close,
	.ndo_start_xmit = kvaser_usb_start_xmit,
	.ndo_hwtstamp_get = can_hwtstamp_get,
	.ndo_hwtstamp_set = can_hwtstamp_set,
};

static const struct ethtool_ops kvaser_usb_ethtool_ops = {
	.get_ts_info = can_ethtool_op_get_ts_info_hwts,
	.set_phys_id = kvaser_usb_set_phys_id,
};

static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
{
	const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
	int i;
	struct kvaser_usb_net_priv *priv;

	for (i = 0; i < dev->nchannels; i++) {
		priv = dev->nets[i];
		if (!priv)
			continue;

		unregister_candev(priv->netdev);
	}

	kvaser_usb_unlink_all_urbs(dev);

	for (i = 0; i < dev->nchannels; i++) {
		priv = dev->nets[i];
		if (!priv)
			continue;

		if (ops->dev_remove_channel)
			ops->dev_remove_channel(priv);

		kvaser_usb_devlink_port_unregister(priv);
		free_candev(priv->netdev);
	}
}

static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
{
	struct net_device *netdev;
	struct kvaser_usb_net_priv *priv;
	const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
	const struct kvaser_usb_dev_ops *ops = driver_info->ops;
	int err;

	if (ops->dev_reset_chip) {
		err = ops->dev_reset_chip(dev, channel);
		if (err)
			return err;
	}

	netdev = alloc_candev(struct_size(priv, tx_contexts, dev->max_tx_urbs),
			      dev->max_tx_urbs);
	if (!netdev) {
		dev_err(&dev->intf->dev, "Cannot alloc candev\n");
		return -ENOMEM;
	}

	priv = netdev_priv(netdev);

	init_usb_anchor(&priv->tx_submitted);
	init_completion(&priv->start_comp);
	init_completion(&priv->stop_comp);
	init_completion(&priv->flush_comp);
	init_completion(&priv->get_busparams_comp);
	priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC |
				       CAN_CTRLMODE_BERR_REPORTING;

	priv->dev = dev;
	priv->netdev = netdev;
	priv->channel = channel;

	spin_lock_init(&priv->tx_contexts_lock);
	kvaser_usb_reset_tx_urb_contexts(priv);

	priv->can.state = CAN_STATE_STOPPED;
	priv->can.clock.freq = dev->cfg->clock.freq;
	priv->can.bittiming_const = dev->cfg->bittiming_const;
	priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
	priv->can.do_set_mode = ops->dev_set_mode;
	if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
	    (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
		priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
	if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
		priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;

Annotation

Implementation Notes