drivers/net/can/usb/nct6694_canfd.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/usb/nct6694_canfd.c
Extension
.c
Size
21297 bytes
Lines
832
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 nct6694_canfd_netdev_ops = {
	.ndo_open = nct6694_canfd_open,
	.ndo_stop = nct6694_canfd_close,
	.ndo_start_xmit = nct6694_canfd_start_xmit,
};

static const struct ethtool_ops nct6694_canfd_ethtool_ops = {
	.get_ts_info = ethtool_op_get_ts_info,
};

static int nct6694_canfd_get_clock(struct nct6694_canfd_priv *priv)
{
	struct nct6694_canfd_information *info __free(kfree) = NULL;
	static const struct nct6694_cmd_header cmd_hd = {
		.mod = NCT6694_CANFD_MOD,
		.cmd = NCT6694_CANFD_INFORMATION,
		.sel = NCT6694_CANFD_INFORMATION_SEL,
		.len = cpu_to_le16(sizeof(*info))
	};
	int ret;

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

	ret = nct6694_read_msg(priv->nct6694, &cmd_hd, info);
	if (ret)
		return ret;

	return le32_to_cpu(info->can_clk);
}

static int nct6694_canfd_probe(struct platform_device *pdev)
{
	struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent);
	struct nct6694_canfd_priv *priv;
	struct net_device *ndev;
	int port, irq, ret, can_clk;

	port = ida_alloc(&nct6694->canfd_ida, GFP_KERNEL);
	if (port < 0)
		return port;

	irq = irq_create_mapping(nct6694->domain,
				 NCT6694_IRQ_CAN0 + port);
	if (!irq) {
		ret = -EINVAL;
		goto free_ida;
	}

	ndev = alloc_candev(sizeof(struct nct6694_canfd_priv), 1);
	if (!ndev) {
		ret = -ENOMEM;
		goto dispose_irq;
	}

	ndev->irq = irq;
	ndev->flags |= IFF_ECHO;
	ndev->dev_port = port;
	ndev->netdev_ops = &nct6694_canfd_netdev_ops;
	ndev->ethtool_ops = &nct6694_canfd_ethtool_ops;

	priv = netdev_priv(ndev);
	priv->nct6694 = nct6694;
	priv->ndev = ndev;

	can_clk = nct6694_canfd_get_clock(priv);
	if (can_clk < 0) {
		ret = dev_err_probe(&pdev->dev, can_clk,
				    "Failed to get clock\n");
		goto free_candev;
	}

	INIT_WORK(&priv->tx_work, nct6694_canfd_tx_work);

	priv->can.clock.freq = can_clk;
	priv->can.bittiming_const = &nct6694_canfd_bittiming_nominal_const;
	priv->can.fd.data_bittiming_const = &nct6694_canfd_bittiming_data_const;
	priv->can.do_set_mode = nct6694_canfd_set_mode;
	priv->can.do_get_berr_counter = nct6694_canfd_get_berr_counter;
	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING |
		CAN_CTRLMODE_FD_NON_ISO;

	ret = can_set_static_ctrlmode(ndev, CAN_CTRLMODE_FD);
	if (ret)
		goto free_candev;

	ret = can_rx_offload_add_manual(ndev, &priv->offload,
					NCT6694_NAPI_WEIGHT);

Annotation

Implementation Notes