static void ecm_disable(struct usb_function *f) { struct f_ecm *ecm = func_to_ecm(f); struct usb_composite_dev *cdev = f->config->cdev; DBG(cdev, "ecm deactivated\n"); if (ecm->port.in_ep->driver_data) gether_disconnect(&ecm->port); if (ecm->notify->driver_data) { usb_ep_disable(ecm->notify); ecm->notify->driver_data = NULL; ecm->notify_desc = NULL; } }
static void rndis_disable(struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; if (!rndis->notify->driver_data) return; DBG(cdev, "rndis deactivated\n"); rndis_uninit(rndis->config); gether_disconnect(&rndis->port); usb_ep_disable(rndis->notify); rndis->notify->driver_data = NULL; }
static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_ecm *ecm = func_to_ecm(f); struct usb_composite_dev *cdev = f->config->cdev; /* Control interface has only altsetting 0 */ if (intf == ecm->ctrl_id) { if (alt != 0) goto fail; if (ecm->notify->driver_data) { VDBG(cdev, "reset ecm control %d\n", intf); usb_ep_disable(ecm->notify); } else { VDBG(cdev, "init ecm ctrl %d\n", intf); ecm->notify_desc = ep_choose(cdev->gadget, ecm->hs.notify, ecm->fs.notify); } usb_ep_enable(ecm->notify, ecm->notify_desc); ecm->notify->driver_data = ecm; /* Data interface has two altsettings, 0 and 1 */ } else if (intf == ecm->data_id) { if (alt > 1) goto fail; if (ecm->port.in_ep->driver_data) { DBG(cdev, "reset ecm\n"); gether_disconnect(&ecm->port); } if (!ecm->port.in) { DBG(cdev, "init ecm\n"); ecm->port.in = ep_choose(cdev->gadget, ecm->hs.in, ecm->fs.in); ecm->port.out = ep_choose(cdev->gadget, ecm->hs.out, ecm->fs.out); } /* CDC Ethernet only sends data in non-default altsettings. * Changing altsettings resets filters, statistics, etc. */ if (alt == 1) { struct net_device *net; #ifdef CONFIG_LGE_USB_GADGET_DRIVER ecm->port.is_zlp_ok = !( gadget_is_musbhdrc(cdev->gadget) || gadget_is_fsl_usb2(cdev->gadget) ); #else /* Enable zlps by default for ECM conformance; * override for musb_hdrc (avoids txdma ovhead). */ ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)); #endif ecm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ecm\n"); net = gether_connect(&ecm->port); if (IS_ERR(net)) return PTR_ERR(net); } /* NOTE this can be a minor disagreement with the ECM spec, * which says speed notifications will "always" follow * connection notifications. But we allow one connect to * follow another (if the first is in flight), and instead * just guarantee that a speed notification is always sent. */ ecm_notify(ecm); } else goto fail; return 0; fail: return -EINVAL; }
static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_rndis *rndis = func_to_rndis(f); struct usb_composite_dev *cdev = f->config->cdev; /* we know alt == 0 */ if (intf == rndis->ctrl_id) { if (rndis->notify->driver_data) { VDBG(cdev, "reset rndis control %d\n", intf); usb_ep_disable(rndis->notify); } if (!rndis->notify->desc) { VDBG(cdev, "init rndis ctrl %d\n", intf); if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) goto fail; } usb_ep_enable(rndis->notify); rndis->notify->driver_data = rndis; } else if (intf == rndis->data_id) { struct net_device *net; rndis->port.rx_triggered = false; if (rndis->port.in_ep->driver_data) { DBG(cdev, "reset rndis\n"); gether_disconnect(&rndis->port); } if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { DBG(cdev, "init rndis\n"); if (config_ep_by_speed(cdev->gadget, f, rndis->port.in_ep) || config_ep_by_speed(cdev->gadget, f, rndis->port.out_ep)) { rndis->port.in_ep->desc = NULL; rndis->port.out_ep->desc = NULL; goto fail; } } /* Avoid ZLPs; they can be troublesome. */ rndis->port.is_zlp_ok = false; /* RNDIS should be in the "RNDIS uninitialized" state, * either never activated or after rndis_uninit(). * * We don't want data to flow here until a nonzero packet * filter is set, at which point it enters "RNDIS data * initialized" state ... but we do want the endpoints * to be activated. It's a strange little state. * * REVISIT the RNDIS gadget code has done this wrong for a * very long time. We need another call to the link layer * code -- gether_updown(...bool) maybe -- to do it right. */ rndis->port.cdc_filter = 0; DBG(cdev, "RNDIS RX/TX early activation ...\n"); gether_enable_sg(&rndis->port, true); net = gether_connect(&rndis->port); if (IS_ERR(net)) return PTR_ERR(net); rndis_set_param_dev(rndis->config, net, &rndis->port.cdc_filter); } else goto fail; return 0; fail: return -EINVAL; }