drivers/net/can/usb/f81604.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/usb/f81604.c
Extension
.c
Size
28598 bytes
Lines
1240
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 f81604_netdev_ops = {
	.ndo_open = f81604_open,
	.ndo_stop = f81604_close,
	.ndo_start_xmit = f81604_start_xmit,
};

static const struct can_bittiming_const f81604_bittiming_const = {
	.name = KBUILD_MODNAME,
	.tseg1_min = 1,
	.tseg1_max = 16,
	.tseg2_min = 1,
	.tseg2_max = 8,
	.sjw_max = 4,
	.brp_min = 1,
	.brp_max = 64,
	.brp_inc = 1,
};

/* Called by the usb core when driver is unloaded or device is removed */
static void f81604_disconnect(struct usb_interface *intf)
{
	struct f81604_priv *priv = usb_get_intfdata(intf);
	int i;

	for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
		if (!priv->netdev[i])
			continue;

		unregister_netdev(priv->netdev[i]);
		free_candev(priv->netdev[i]);
	}
}

static int __f81604_set_termination(struct usb_device *dev, int idx, u16 term)
{
	u8 mask, data = 0;

	if (idx == 0)
		mask = F81604_CAN0_TERM;
	else
		mask = F81604_CAN1_TERM;

	if (term)
		data = mask;

	return f81604_update_bits(dev, F81604_TERMINATOR_REG, mask, data);
}

static int f81604_set_termination(struct net_device *netdev, u16 term)
{
	struct f81604_port_priv *port_priv = netdev_priv(netdev);

	ASSERT_RTNL();

	return __f81604_set_termination(port_priv->dev, netdev->dev_port,
					term);
}

static int f81604_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	struct net_device *netdev;
	struct f81604_priv *priv;
	int i, ret;

	priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	usb_set_intfdata(intf, priv);

	for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
		ret = __f81604_set_termination(dev, i, 0);
		if (ret) {
			dev_err(&intf->dev,
				"Setting termination of CH#%d failed: %pe\n",
				i, ERR_PTR(ret));
			return ret;
		}
	}

	for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
		struct f81604_port_priv *port_priv;

		netdev = alloc_candev(sizeof(*port_priv), 1);
		if (!netdev) {
			dev_err(&intf->dev, "Couldn't alloc candev: %d\n", i);
			ret = -ENOMEM;

Annotation

Implementation Notes