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), 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; /* no need to put the VLAN tci in the packet headers */ dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER; /* monitor VLAN additions and removals */ dev->net->netdev_ops = &cdc_mbim_netdev_ops; err: return ret; }
/* Some devices combine the "control" and "data" functions into a * single interface with all three endpoints: interrupt + bulk in and * out * * Setting up cdc-wdm as a subdriver owning the interrupt endpoint * will let it provide userspace access to the encapsulated QMI * protocol without interfering with the usbnet operations. */ static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) { int rv; struct usb_driver *subdriver = NULL; atomic_t *pmcount = (void *)&dev->data[1]; /* ZTE makes devices where the interface descriptors and endpoint * configurations of two or more interfaces are identical, even * though the functions are completely different. If set, then * driver_info->data is a bitmap of acceptable interface numbers * allowing us to bind to one such interface without binding to * all of them */ if (dev->driver_info->data && !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) { dev_info(&intf->dev, "not on our whitelist - ignored"); rv = -ENODEV; goto err; } atomic_set(pmcount, 0); /* collect all three endpoints */ rv = usbnet_get_endpoints(dev, intf); if (rv < 0) goto err; /* require interrupt endpoint for subdriver */ if (!dev->status) { rv = -EINVAL; goto err; } subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power); if (IS_ERR(subdriver)) { rv = PTR_ERR(subdriver); goto err; } /* can't let usbnet use the interrupt endpoint */ dev->status = NULL; /* save subdriver struct for suspend/resume wrappers */ dev->data[0] = (unsigned long)subdriver; err: return rv; }
static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf) { struct cdc_ncm_ctx *ctx; struct usb_driver *subdriver = ERR_PTR(-ENODEV); int ret = -ENODEV; struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; int drvflags = 0; /* altsetting should always be 1 for NCM devices - so we hard-coded * it here. Some huawei devices will need the NDP part of the NCM package to * be at the end of the frame. */ drvflags |= CDC_NCM_FLAG_NDP_TO_END; ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); if (ret) goto err; ctx = drvstate->ctx; if (usbnet_dev->status) /* The wMaxCommand buffer must be big enough to hold * any message from the modem. Experience has shown * that some replies are more than 256 bytes long */ subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, 1024, /* wMaxCommand */ huawei_cdc_ncm_wdm_manage_power); if (IS_ERR(subdriver)) { ret = PTR_ERR(subdriver); cdc_ncm_unbind(usbnet_dev, intf); goto err; } /* Prevent usbnet from using the status descriptor */ usbnet_dev->status = NULL; drvstate->subdriver = subdriver; err: return ret; }
/* collect all three endpoints and register subdriver */ static int qmi_wwan_register_subdriver(struct usbnet *dev) { int rv; struct usb_driver *subdriver = NULL; struct qmi_wwan_state *info = (void *)&dev->data; /* collect bulk endpoints */ rv = usbnet_get_endpoints(dev, info->data); if (rv < 0) goto err; /* update status endpoint if separate control interface */ if (info->control != info->data) dev->status = &info->control->cur_altsetting->endpoint[0]; /* require interrupt endpoint for subdriver */ if (!dev->status) { rv = -EINVAL; goto err; } /* for subdriver power management */ atomic_set(&info->pmcount, 0); /* register subdriver */ subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, 4096, &qmi_wwan_cdc_wdm_manage_power); if (IS_ERR(subdriver)) { dev_err(&info->control->dev, "subdriver registration failed\n"); rv = PTR_ERR(subdriver); goto err; } /* prevent usbnet from using status endpoint */ dev->status = NULL; /* save subdriver struct for suspend/resume wrappers */ info->subdriver = subdriver; err: return rv; }
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 = cdc_ncm_select_altsetting(dev, intf); struct cdc_mbim_state *info = (void *)&dev->data; /* Probably NCM, defer for cdc_ncm_bind */ if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) goto err; ret = cdc_ncm_bind_common(dev, intf, data_altsetting); 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), 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; /* no need to put the VLAN tci in the packet headers */ dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX; err: return ret; }
static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf) { struct cdc_ncm_ctx *ctx; struct usb_driver *subdriver = ERR_PTR(-ENODEV); int ret = -ENODEV; struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; /* altsetting should always be 1 for NCM devices - so we hard-coded * it here */ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); if (ret) goto err; ctx = drvstate->ctx; if (usbnet_dev->status) /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 * decimal (0x100)" */ subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, 256, /* wMaxCommand */ huawei_cdc_ncm_wdm_manage_power); if (IS_ERR(subdriver)) { ret = PTR_ERR(subdriver); cdc_ncm_unbind(usbnet_dev, intf); goto err; } /* Prevent usbnet from using the status descriptor */ usbnet_dev->status = NULL; drvstate->subdriver = subdriver; err: return ret; }