drivers/net/can/usb/mcba_usb.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/usb/mcba_usb.c
Extension
.c
Size
21536 bytes
Lines
920
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 mcba_netdev_ops = {
	.ndo_open = mcba_usb_open,
	.ndo_stop = mcba_usb_close,
	.ndo_start_xmit = mcba_usb_start_xmit,
};

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

/* Microchip CANBUS has hardcoded bittiming values by default.
 * This function sends request via USB to change the speed and align bittiming
 * values for presentation purposes only
 */
static int mcba_net_set_bittiming(struct net_device *netdev)
{
	struct mcba_priv *priv = netdev_priv(netdev);
	const u16 bitrate_kbps = priv->can.bittiming.bitrate / 1000;

	mcba_usb_xmit_change_bitrate(priv, bitrate_kbps);

	return 0;
}

static int mcba_set_termination(struct net_device *netdev, u16 term)
{
	struct mcba_priv *priv = netdev_priv(netdev);
	struct mcba_usb_msg_termination usb_msg = {
		.cmd_id = MBCA_CMD_SETUP_TERMINATION_RESISTANCE
	};

	if (term == MCBA_TERMINATION_ENABLED)
		usb_msg.termination = MCBA_VER_TERMINATION_ON;
	else
		usb_msg.termination = MCBA_VER_TERMINATION_OFF;

	mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);

	return 0;
}

static int mcba_usb_probe(struct usb_interface *intf,
			  const struct usb_device_id *id)
{
	struct net_device *netdev;
	struct mcba_priv *priv;
	int err;
	struct usb_device *usbdev = interface_to_usbdev(intf);
	struct usb_endpoint_descriptor *in, *out;

	err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL);
	if (err) {
		dev_err(&intf->dev, "Can't find endpoints\n");
		return err;
	}

	netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS);
	if (!netdev) {
		dev_err(&intf->dev, "Couldn't alloc candev\n");
		return -ENOMEM;
	}

	priv = netdev_priv(netdev);

	priv->udev = usbdev;
	priv->netdev = netdev;
	priv->usb_ka_first_pass = true;
	priv->can_ka_first_pass = true;
	priv->can_speed_check = false;

	init_usb_anchor(&priv->rx_submitted);
	init_usb_anchor(&priv->tx_submitted);

	usb_set_intfdata(intf, priv);

	/* Init CAN device */
	priv->can.state = CAN_STATE_STOPPED;
	priv->can.termination_const = mcba_termination;
	priv->can.termination_const_cnt = ARRAY_SIZE(mcba_termination);
	priv->can.bitrate_const = mcba_bitrate;
	priv->can.bitrate_const_cnt = ARRAY_SIZE(mcba_bitrate);

	priv->can.do_set_termination = mcba_set_termination;
	priv->can.do_set_mode = mcba_net_set_mode;
	priv->can.do_get_berr_counter = mcba_net_get_berr_counter;
	priv->can.do_set_bittiming = mcba_net_set_bittiming;

	netdev->netdev_ops = &mcba_netdev_ops;
	netdev->ethtool_ops = &mcba_ethtool_ops;

Annotation

Implementation Notes