drivers/net/usb/cdc_mbim.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/usb/cdc_mbim.c
Extension
.c
Size
19946 bytes
Lines
700
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 cdc_mbim_netdev_ops = {
	.ndo_open             = usbnet_open,
	.ndo_stop             = usbnet_stop,
	.ndo_start_xmit       = usbnet_start_xmit,
	.ndo_tx_timeout       = usbnet_tx_timeout,
	.ndo_get_stats64      = dev_get_tstats64,
	.ndo_change_mtu       = cdc_ncm_change_mtu,
	.ndo_set_mac_address  = eth_mac_addr,
	.ndo_validate_addr    = eth_validate_addr,
	.ndo_vlan_rx_add_vid  = cdc_mbim_rx_add_vid,
	.ndo_vlan_rx_kill_vid = cdc_mbim_rx_kill_vid,
};

/* Change the control interface altsetting and update the .driver_info
 * pointer if the matching entry after changing class codes points to
 * a different struct
 */
static int cdc_mbim_set_ctrlalt(struct usbnet *dev, struct usb_interface *intf, u8 alt)
{
	struct usb_driver *driver = to_usb_driver(intf->dev.driver);
	const struct usb_device_id *id;
	struct driver_info *info;
	int ret;

	ret = usb_set_interface(dev->udev,
				intf->cur_altsetting->desc.bInterfaceNumber,
				alt);
	if (ret)
		return ret;

	id = usb_match_id(intf, driver->id_table);
	if (!id)
		return -ENODEV;

	info = (struct driver_info *)id->driver_info;
	if (info != dev->driver_info) {
		dev_dbg(&intf->dev, "driver_info updated to '%s'\n",
			info->description);
		dev->driver_info = info;
	}
	return 0;
}

static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
{
	struct cdc_ncm_ctx *ctx;
	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
	int ret = -ENODEV;
	u8 data_altsetting = 1;
	struct cdc_mbim_state *info = (void *)&dev->data;

	/* should we change control altsetting on a NCM/MBIM function? */
	if (cdc_ncm_select_altsetting(intf) == CDC_NCM_COMM_ALTSETTING_MBIM) {
		data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
		ret = cdc_mbim_set_ctrlalt(dev, intf, CDC_NCM_COMM_ALTSETTING_MBIM);
		if (ret)
			goto err;
		ret = -ENODEV;
	}

	/* we will hit this for NCM/MBIM functions if prefer_mbim is false */
	if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
		goto err;

	ret = cdc_ncm_bind_common(dev, intf, data_altsetting, dev->driver_info->data);
	if (ret)
		goto err;

	ctx = info->ctx;

	/* The MBIM descriptor and the status endpoint are required */
	if (ctx->mbim_desc && dev->status)
		subdriver = usb_cdc_wdm_register(ctx->control,
						 &dev->status->desc,
						 le16_to_cpu(ctx->mbim_desc->wMaxControlMessage),
						 WWAN_PORT_MBIM,
						 cdc_mbim_wdm_manage_power);
	if (IS_ERR(subdriver)) {
		ret = PTR_ERR(subdriver);
		cdc_ncm_unbind(dev, intf);
		goto err;
	}

	/* can't let usbnet use the interrupt endpoint */
	dev->status = NULL;
	info->subdriver = subdriver;

	/* MBIM cannot do ARP */
	dev->net->flags |= IFF_NOARP;

Annotation

Implementation Notes