Exemple #1
0
static int
usie_attach(device_t self)
{
	struct usie_softc *sc = device_get_softc(self);
	struct usb_attach_arg *uaa = device_get_ivars(self);
	struct ifnet *ifp;
	struct usb_interface *iface;
	struct usb_interface_descriptor *id;
	struct usb_device_request req;
	int err;
	uint16_t fwattr;
	uint8_t iface_index;
	uint8_t ifidx;
	uint8_t start;

	device_set_usb_desc(self);
	sc->sc_udev = uaa->device;
	sc->sc_dev = self;

	mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF);

	TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc);
	TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc);

	usb_callout_init_mtx(&sc->sc_if_sync_ch, &sc->sc_mtx, 0);

	mtx_lock(&sc->sc_mtx);

	/* set power mode to D0 */
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = USIE_POWER;
	USETW(req.wValue, 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, 0);
	if (usie_do_request(sc, &req, NULL)) {
		mtx_unlock(&sc->sc_mtx);
		goto detach;
	}
	/* read fw attr */
	fwattr = 0;
	req.bmRequestType = UT_READ_VENDOR_DEVICE;
	req.bRequest = USIE_FW_ATTR;
	USETW(req.wValue, 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, sizeof(fwattr));
	if (usie_do_request(sc, &req, &fwattr)) {
		mtx_unlock(&sc->sc_mtx);
		goto detach;
	}
	mtx_unlock(&sc->sc_mtx);

	/* check DHCP supports */
	DPRINTF("fwattr=%x\n", fwattr);
	if (!(fwattr & USIE_FW_DHCP)) {
		device_printf(self, "DHCP is not supported. A firmware upgrade might be needed.\n");
	}

	/* find available interfaces */
	sc->sc_nucom = 0;
	for (ifidx = 0; ifidx < USIE_IFACE_MAX; ifidx++) {
		iface = usbd_get_iface(uaa->device, ifidx);
		if (iface == NULL)
			break;

		id = usbd_get_interface_descriptor(iface);
		if ((id == NULL) || (id->bInterfaceClass != UICLASS_VENDOR))
			continue;

		/* setup Direct IP transfer */
		if (id->bInterfaceNumber >= 7 && id->bNumEndpoints == 3) {
			sc->sc_if_ifnum = id->bInterfaceNumber;
			iface_index = ifidx;

			DPRINTF("ifnum=%d, ifidx=%d\n",
			    sc->sc_if_ifnum, ifidx);

			err = usbd_transfer_setup(uaa->device,
			    &iface_index, sc->sc_if_xfer, usie_if_config,
			    USIE_IF_N_XFER, sc, &sc->sc_mtx);

			if (err == 0)
				continue;

			device_printf(self,
			    "could not allocate USB transfers on "
			    "iface_index=%d, err=%s\n",
			    iface_index, usbd_errstr(err));
			goto detach;
		}

		/* setup ucom */
		if (sc->sc_nucom >= USIE_UCOM_MAX)
			continue;

		usbd_set_parent_iface(uaa->device, ifidx,
		    uaa->info.bIfaceIndex);

		DPRINTF("NumEndpoints=%d bInterfaceNumber=%d\n",
		    id->bNumEndpoints, id->bInterfaceNumber);

		if (id->bNumEndpoints == 2) {
			sc->sc_uc_xfer[sc->sc_nucom][0] = NULL;
			start = 1;
		} else
			start = 0;

		err = usbd_transfer_setup(uaa->device, &ifidx,
		    sc->sc_uc_xfer[sc->sc_nucom] + start,
		    usie_uc_config + start, USIE_UC_N_XFER - start,
		    &sc->sc_ucom[sc->sc_nucom], &sc->sc_mtx);

		if (err != 0) {
			DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
			continue;
		}

		mtx_lock(&sc->sc_mtx);
		for (; start < USIE_UC_N_XFER; start++)
			usbd_xfer_set_stall(sc->sc_uc_xfer[sc->sc_nucom][start]);
		mtx_unlock(&sc->sc_mtx);

		sc->sc_uc_ifnum[sc->sc_nucom] = id->bInterfaceNumber;

		sc->sc_nucom++;		/* found a port */
	}

	if (sc->sc_nucom == 0) {
		device_printf(self, "no comports found\n");
		goto detach;
	}

	err = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
	    sc->sc_nucom, sc, &usie_uc_callback, &sc->sc_mtx);

	if (err != 0) {
		DPRINTF("ucom_attach failed\n");
		goto detach;
	}
	DPRINTF("Found %d interfaces.\n", sc->sc_nucom);

	/* setup ifnet (Direct IP) */
	sc->sc_ifp = ifp = if_alloc(IFT_OTHER);

	if (ifp == NULL) {
		device_printf(self, "Could not allocate a network interface\n");
		goto detach;
	}
	if_initname(ifp, "usie", device_get_unit(self));

	ifp->if_softc = sc;
	ifp->if_mtu = USIE_MTU_MAX;
	ifp->if_flags |= IFF_NOARP;
	ifp->if_init = usie_if_init;
	ifp->if_ioctl = usie_if_ioctl;
	ifp->if_start = usie_if_start;
	ifp->if_output = usie_if_output;
	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
	IFQ_SET_READY(&ifp->if_snd);

	if_attach(ifp);
	bpfattach(ifp, DLT_RAW, 0);

	if (fwattr & USIE_PM_AUTO) {
		usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
		DPRINTF("enabling automatic suspend and resume\n");
	} else {
		usbd_set_power_mode(uaa->device, USB_POWER_MODE_ON);
		DPRINTF("USB power is always ON\n");
	}

	DPRINTF("device attached\n");
	return (0);

detach:
	usie_detach(self);
	return (ENOMEM);
}
static int
ugen_set_power_mode(struct usb_fifo *f, int mode)
{
	struct usb_device *udev = f->udev;
	int err;
	uint8_t old_mode;

	if ((udev == NULL) ||
	    (udev->parent_hub == NULL)) {
		return (EINVAL);
	}
	err = priv_check(curthread, PRIV_DRIVER);
	if (err)
		return (err);

	/* get old power mode */
	old_mode = udev->power_mode;

	/* if no change, then just return */
	if (old_mode == mode)
		return (0);

	switch (mode) {
	case USB_POWER_MODE_OFF:
		/* get the device unconfigured */
		err = ugen_set_config(f, USB_UNCONFIG_INDEX);
		if (err) {
			DPRINTFN(0, "Could not unconfigure "
			    "device (ignored)\n");
		}

		/* clear port enable */
		err = usbd_req_clear_port_feature(udev->parent_hub,
		    NULL, udev->port_no, UHF_PORT_ENABLE);
		break;

	case USB_POWER_MODE_ON:
	case USB_POWER_MODE_SAVE:
		break;

	case USB_POWER_MODE_RESUME:
		err = usbd_req_clear_port_feature(udev->parent_hub,
		    NULL, udev->port_no, UHF_PORT_SUSPEND);
		mode = USB_POWER_MODE_SAVE;
		break;

	case USB_POWER_MODE_SUSPEND:
		err = usbd_req_set_port_feature(udev->parent_hub,
		    NULL, udev->port_no, UHF_PORT_SUSPEND);
		mode = USB_POWER_MODE_SAVE;
		break;

	default:
		return (EINVAL);
	}

	if (err)
		return (ENXIO);		/* I/O failure */

	/* if we are powered off we need to re-enumerate first */
	if (old_mode == USB_POWER_MODE_OFF) {
		err = ugen_re_enumerate(f);
		if (err)
			return (err);
	}

	/* set new power mode */
	usbd_set_power_mode(udev, mode);

	return (0);			/* success */
}
Exemple #3
0
static int
ugen_set_power_mode(struct usb_fifo *f, int mode)
{
	struct usb_device *udev = f->udev;
	int err;
	uint8_t old_mode;

	if ((udev == NULL) ||
	    (udev->parent_hub == NULL)) {
		return (EINVAL);
	}
	err = priv_check(curthread, PRIV_DRIVER);
	if (err)
		return (err);

	/* get old power mode */
	old_mode = udev->power_mode;

	/* if no change, then just return */
	if (old_mode == mode)
		return (0);

	switch (mode) {
	case USB_POWER_MODE_OFF:
		/* get the device unconfigured */
		err = ugen_set_config(f, USB_UNCONFIG_INDEX);
		if (err) {
			DPRINTFN(0, "Could not unconfigure "
			    "device (ignored)\n");
		}

		/* clear port enable */
		err = usbd_req_clear_port_feature(udev->parent_hub,
		    NULL, udev->port_no, UHF_PORT_ENABLE);
		break;

	case USB_POWER_MODE_ON:
	case USB_POWER_MODE_SAVE:
		break;

	case USB_POWER_MODE_RESUME:
#if USB_HAVE_POWERD
		/* let USB-powerd handle resume */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.write_refs++;
		udev->pwr_save.last_xfer_time = ticks;
		USB_BUS_UNLOCK(udev->bus);

		/* set new power mode */
		usbd_set_power_mode(udev, USB_POWER_MODE_SAVE);

		/* wait for resume to complete */
		usb_pause_mtx(NULL, hz / 4);

		/* clear write reference */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.write_refs--;
		USB_BUS_UNLOCK(udev->bus);
#endif
		mode = USB_POWER_MODE_SAVE;
		break;

	case USB_POWER_MODE_SUSPEND:
#if USB_HAVE_POWERD
		/* let USB-powerd handle suspend */
		USB_BUS_LOCK(udev->bus);
		udev->pwr_save.last_xfer_time = ticks - (256 * hz);
		USB_BUS_UNLOCK(udev->bus);
#endif
		mode = USB_POWER_MODE_SAVE;
		break;

	default:
		return (EINVAL);
	}

	if (err)
		return (ENXIO);		/* I/O failure */

	/* if we are powered off we need to re-enumerate first */
	if (old_mode == USB_POWER_MODE_OFF) {
		if (udev->flags.usb_mode == USB_MODE_HOST) {
			if (udev->re_enumerate_wait == 0)
				udev->re_enumerate_wait = 1;
		}
		/* set power mode will wake up the explore thread */
	}

	/* set new power mode */
	usbd_set_power_mode(udev, mode);

	return (0);			/* success */
}