Example #1
0
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;
}
Example #3
0
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;
}