Exemplo n.º 1
0
usbd_status
usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
{
	usb_device_request_t req;
	usbd_status err;
	int n;

	req.bmRequestType = UT_WRITE_CLASS_OTHER;
	req.bRequest = UR_SET_FEATURE;
	USETW(req.wValue, UHF_PORT_RESET);
	USETW(req.wIndex, port);
	USETW(req.wLength, 0);
	err = usbd_do_request(dev, &req, 0);
	DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
		    port, usbd_errstr(err)));
	if (err)
		return (err);
	n = 10;
	do {
		/* Wait for device to recover from reset. */
		usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
		err = usbd_get_port_status(dev, port, ps);
		if (err) {
			DPRINTF(("usbd_reset_port: get status failed %d\n",
				 err));
			return (err);
		}
		/* If the device disappeared, just give up. */
		if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
			return (USBD_NORMAL_COMPLETION);
	} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
	if (n == 0)
		return (USBD_TIMEOUT);
	err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
#ifdef USB_DEBUG
	if (err)
		DPRINTF(("usbd_reset_port: clear port feature failed %d\n",
			 err));
#endif

	/* Wait for the device to recover from reset. */
	usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
	return (err);
}
Exemplo n.º 2
0
void
emdtv_dtv_attach(struct emdtv_softc *sc)
{
	usb_endpoint_descriptor_t *ed;
	usbd_status status;
	int i;

	for (i = 0; i < EMDTV_NXFERS; i++) {
		sc->sc_ix[i].ix_altix = (i & 1) ?
		    &sc->sc_ix[i - 1] : &sc->sc_ix[i + 1];
		sc->sc_ix[i].ix_sc = sc;
	}

	ed = usbd_interface2endpoint_descriptor(sc->sc_iface, 3);
	if (ed == NULL) {
		aprint_error_dev(sc->sc_dev, "couldn't find endpoint 3\n");
		return;
	}
	sc->sc_isoc_maxpacketsize = UGETW(ed->wMaxPacketSize);
	sc->sc_isoc_buflen = sc->sc_isoc_maxpacketsize * EMDTV_NFRAMES;

	aprint_debug_dev(sc->sc_dev, "calling usbd_open_pipe, ep 0x%02x\n",
	    ed->bEndpointAddress);
	status = usbd_open_pipe(sc->sc_iface,
	    ed->bEndpointAddress, USBD_EXCLUSIVE_USE|USBD_MPSAFE,
	    &sc->sc_isoc_pipe);
	if (status != USBD_NORMAL_COMPLETION) {
		aprint_error_dev(sc->sc_dev, "couldn't open isoc pipe\n");
		usbd_set_interface(sc->sc_iface, 0);
		return;
	}

	emdtv_write_1(sc, UR_GET_STATUS, 0x48, 0x00);
	emdtv_write_1(sc, UR_GET_STATUS, 0x12, 0x77);
	usbd_delay_ms(sc->sc_udev, 6);

	emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, false);
	emdtv_gpio_ctl(sc, EMDTV_GPIO_TS1_ON, true);
	emdtv_gpio_ctl(sc, EMDTV_GPIO_TUNER1_ON, true);
	emdtv_gpio_ctl(sc, EMDTV_GPIO_DEMOD1_RESET, true);
	usbd_delay_ms(sc->sc_udev, 100);

	emdtv_dtv_rescan(sc, NULL, NULL);
}
Exemplo n.º 3
0
int
uoak_get_cmd(struct uoak_softc *sc)
{
	sc->sc_rcmd.dir = OAK_GET;

	/* check the device is ready to request */
	while (uoak_check_device_ready(sc) < 0) 
		usbd_delay_ms(sc->sc_udev, UOAK_RETRY_DELAY);

	/* issue request */
	if (uhidev_set_report(sc->sc_hdev, UHID_FEATURE_REPORT,
	    &sc->sc_rcmd, sc->sc_flen))
		return EIO;

	/* wait till the device ready to return the request */
	while (uoak_check_device_ready(sc) < 0) 
		usbd_delay_ms(sc->sc_udev, UOAK_RESPONSE_DELAY); 

	return 0;
}
Exemplo n.º 4
0
/*
 * Issue a SET_CONFIGURATION command to reset the MAC. This should be
 * done after the firmware is loaded into the adapter in order to
 * bring it into proper operation.
 */
void
kue_reset(struct kue_softc *sc)
{
	DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));

	if (usbd_set_config_no(sc->kue_udev, KUE_CONFIG_NO, 1) ||
	    usbd_device2interface_handle(sc->kue_udev, KUE_IFACE_IDX,
					 &sc->kue_iface))
		printf("%s: reset failed\n", sc->kue_dev.dv_xname);

	/* Wait a little while for the chip to get its brains in order. */
	usbd_delay_ms(sc->kue_udev, 10);
}
Exemplo n.º 5
0
int
uoak_set_cmd(struct uoak_softc *sc)
{
	sc->sc_rcmd.dir = OAK_SET;

	while (uoak_check_device_ready(sc) < 0)
		usbd_delay_ms(sc->sc_udev, UOAK_RETRY_DELAY);

	if (uhidev_set_report(sc->sc_hdev, UHID_FEATURE_REPORT,
	    &sc->sc_rcmd, sc->sc_flen))
		return EIO;

	return 0;
}
Exemplo n.º 6
0
usbd_status
ezload_downloads_and_reset(usbd_device_handle dev, const struct ezdata **recs)
{
	usbd_status err;

	/*(void)ezload_reset(dev, 1);*/
	err = ezload_reset(dev, 1);
	if (err)
		return (err);
	usbd_delay_ms(dev, 250);
	while (*recs != NULL) {
		err = ezload_download(dev, *recs++);
		if (err)
			return (err);
	}
	if (err)
		return (err);
	usbd_delay_ms(dev, 250);
	/*(void)ezload_reset(dev, 0);*/
	err = ezload_reset(dev, 0);
	usbd_delay_ms(dev, 250);
	return (err);
}
Exemplo n.º 7
0
void
ueagle_stat_thread(void *arg)
{
	struct ueagle_softc *sc = arg;

	for (;;) {
		if (ueagle_stat(sc) != 0)
			break;

		usbd_delay_ms(sc->sc_udev, 5000);
		if (usbd_is_dying(sc->sc_udev))
			break;
	}

	wakeup(sc->stat_thread);

	kthread_exit(0);
}
Exemplo n.º 8
0
usbd_status
usbd_reload_device_desc(usbd_device_handle dev)
{
	usbd_status err;
	int i;

	/* Get the full device descriptor. */
	for (i = 0; i < 3; ++i) {
		err = usbd_get_device_desc(dev, &dev->ddesc);
		if (!err)
			break;
 		usbd_delay_ms(dev, 200);
	}
	if (err)
		return (err);

	/* Figure out what's wrong with this device. */
	dev->quirks = usbd_find_quirk(&dev->ddesc);

	return (USBD_NORMAL_COMPLETION);
}
Exemplo n.º 9
0
static int
auvitek_stop_xfer(struct auvitek_softc *sc)
{
	struct auvitek_xfer *ax = &sc->sc_ax;
	usbd_status err;
	int i;

	if (ax->ax_pipe != NULL) {
		usbd_abort_pipe(ax->ax_pipe);
		usbd_close_pipe(ax->ax_pipe);
		ax->ax_pipe = NULL;
	}

	for (i = 0; i < AUVITEK_NISOC_XFERS; i++) {
		struct auvitek_isoc *isoc = &ax->ax_i[i];
		if (isoc->i_xfer != NULL) {
			usbd_free_buffer(isoc->i_xfer);
			usbd_free_xfer(isoc->i_xfer);
			isoc->i_xfer = NULL;
		}
		if (isoc->i_frlengths != NULL) {
			kmem_free(isoc->i_frlengths,
			    sizeof(isoc->i_frlengths[0]) * ax->ax_nframes);
			isoc->i_frlengths = NULL;
		}
	}

	usbd_delay_ms(sc->sc_udev, 1000);
	err = usbd_set_interface(sc->sc_isoc_iface, 0);
	if (err != USBD_NORMAL_COMPLETION) {
		aprint_error_dev(sc->sc_dev,
		    "couldn't set zero bw interface: %s\n",
		    usbd_errstr(err));
		return EIO;
	}

	return 0;
}
Exemplo n.º 10
0
static int
uhub_attach(device_t self)
{
	struct uhub_softc *sc = device_get_softc(self);
	struct usb_attach_arg *uaa = device_get_ivars(self);
	usbd_device_handle dev = uaa->device;
	usbd_status err;
	struct usbd_hub *hub = NULL;
	usb_device_request_t req;
	usb_hub_descriptor_t hubdesc;
	int p, port, nports, nremov, pwrdly;
	usbd_interface_handle iface;
	usb_endpoint_descriptor_t *ed;
	struct usbd_tt *tts = NULL;

	DPRINTFN(1,("uhub_attach\n"));
	sc->sc_hub = dev;

	if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
		device_printf(self,
		    "%s transaction translator%s\n",
		    UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
		    UHUB_IS_SINGLE_TT(sc) ? "" : "s");
	}
	err = usbd_set_config_index(dev, 0, 1);
	if (err) {
		DPRINTF(("%s: configuration failed, error=%s\n",
			 device_get_nameunit(self), usbd_errstr(err)));
		return ENXIO;
	}

	if (dev->depth > USB_HUB_MAX_DEPTH) {
		device_printf(self,
		    "hub depth (%d) exceeded, hub ignored\n",
		    USB_HUB_MAX_DEPTH);
		return ENXIO;
	}

	/* Get hub descriptor. */
	req.bmRequestType = UT_READ_CLASS_DEVICE;
	req.bRequest = UR_GET_DESCRIPTOR;
	USETW2(req.wValue, (dev->address > 1 ? UDESC_HUB : 0), 0);
	USETW(req.wIndex, 0);
	USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
	DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
	err = usbd_do_request(dev, &req, &hubdesc);
	nports = hubdesc.bNbrPorts;
	if (!err && nports > 7) {
		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
		err = usbd_do_request(dev, &req, &hubdesc);
	}
	if (err) {
		DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
			 device_get_nameunit(self), usbd_errstr(err)));
		return ENXIO;
	}

	for (nremov = 0, port = 1; port <= nports; port++)
		if (!UHD_NOT_REMOV(&hubdesc, port))
			nremov++;
	device_printf(self,
	    "%d port%s with %d removable, %s powered\n",
	    nports, nports != 1 ? "s" : "",
	    nremov, dev->self_powered ? "self" : "bus");

	if (nports == 0) {
		device_printf(self, "no ports, hub ignored\n");
		goto bad;
	}

	hub = kmalloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
		     M_USBDEV, M_WAITOK);
	dev->hub = hub;
	dev->hub->hubdev = self; 
	hub->explore = uhub_explore;
	hub->hubdesc = hubdesc;

	DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
		    "parent->selfpowered=%d\n",
		 dev->self_powered, dev->powersrc->parent,
		 dev->powersrc->parent ?
		 dev->powersrc->parent->self_powered : 0));

	if (!dev->self_powered && dev->powersrc->parent != NULL &&
	    !dev->powersrc->parent->self_powered) {
		device_printf(self,
		    "bus powered hub connected to bus powered hub, "
		    "ignored\n");
		goto bad;
	}

	/* Set up interrupt pipe. */
	err = usbd_device2interface_handle(dev, 0, &iface);
	if (err) {
		device_printf(self, "no interface handle\n");
		goto bad;
	}
	ed = usbd_interface2endpoint_descriptor(iface, 0);
	if (ed == NULL) {
		device_printf(self, "no endpoint descriptor\n");
		goto bad;
	}
	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
		device_printf(self, "bad interrupt endpoint\n");
		goto bad;
	}

	err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status,
		  sizeof(sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL);
	if (err) {
		device_printf(self, "cannot open interrupt pipe\n");
		goto bad;
	}

	/* Wait with power off for a while. */
	usbd_delay_ms(dev, USB_POWER_DOWN_TIME);

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, self);

	/*
	 * To have the best chance of success we do things in the exact same
	 * order as Windoze98.  This should not be necessary, but some
	 * devices do not follow the USB specs to the letter.
	 *
	 * These are the events on the bus when a hub is attached:
	 *  Get device and config descriptors (see attach code)
	 *  Get hub descriptor (see above)
	 *  For all ports
	 *     turn on power
	 *     wait for power to become stable
	 * (all below happens in explore code)
	 *  For all ports
	 *     clear C_PORT_CONNECTION
	 *  For all ports
	 *     get port status
	 *     if device connected
	 *        wait 100 ms
	 *        turn on reset
	 *        wait
	 *        clear C_PORT_RESET
	 *        get port status
	 *        proceed with device attachment
	 */

	if (UHUB_IS_HIGH_SPEED(sc)) {
		tts = kmalloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
			      sizeof(struct usbd_tt), M_USBDEV, M_WAITOK);
	}

	/* Set up data structures */
	for (p = 0; p < nports; p++) {
		struct usbd_port *up = &hub->ports[p];
		up->device = NULL;
		up->parent = dev;
		up->portno = p+1;
		if (dev->self_powered)
			/* Self powered hub, give ports maximum current. */
			up->power = USB_MAX_POWER;
		else
			up->power = USB_MIN_POWER;
		up->restartcnt = 0;
		if (UHUB_IS_HIGH_SPEED(sc)) {
			up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
			up->tt->hub = hub;
		} else {
			up->tt = NULL;
		}
	}

	/* XXX should check for none, individual, or ganged power? */

	pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
	    + USB_EXTRA_POWER_UP_TIME;
	for (port = 1; port <= nports; port++) {
		/* Turn the power on. */
		err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
		if (err)
			device_printf(self,
			    "port %d power on failed, %s\n",
			    port, usbd_errstr(err));
		DPRINTF(("usb_init_port: turn on port %d power\n", port));
	}

	/* Wait for stable power if we are not a root hub */
	if (dev->powersrc->parent != NULL)
		usbd_delay_ms(dev, pwrdly);

	/* The usual exploration will finish the setup. */

	sc->sc_running = 1;

	return 0;

 bad:
	if (hub)
		kfree(hub, M_USBDEV);
	dev->hub = NULL;
	return ENXIO;
}
Exemplo n.º 11
0
Static int
kue_load_fw(struct kue_softc *sc)
{
	usb_device_descriptor_t dd;
	usbd_status		err;

	DPRINTFN(1,("%s: %s: enter\n", USBDEVNAME(sc->kue_dev), __func__));

	/*
	 * First, check if we even need to load the firmware.
	 * If the device was still attached when the system was
	 * rebooted, it may already have firmware loaded in it.
	 * If this is the case, we don't need to do it again.
	 * And in fact, if we try to load it again, we'll hang,
	 * so we have to avoid this condition if we don't want
	 * to look stupid.
	 *
	 * We can test this quickly by checking the bcdRevision
	 * code. The NIC will return a different revision code if
	 * it's probed while the firmware is still loaded and
	 * running.
	 */
	if (usbd_get_device_desc(sc->kue_udev, &dd))
		return (EIO);
	if (UGETW(dd.bcdDevice) == KUE_WARM_REV) {
		printf("%s: warm boot, no firmware download\n",
		       USBDEVNAME(sc->kue_dev));
		return (0);
	}

	printf("%s: cold boot, downloading firmware\n",
	       USBDEVNAME(sc->kue_dev));

	/* Load code segment */
	DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	/*XXXUNCONST*/
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, __UNCONST(kue_code_seg), sizeof(kue_code_seg));
	if (err) {
		printf("%s: failed to load code segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	/* Load fixup segment */
	DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	/*XXXUNCONST*/
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, __UNCONST(kue_fix_seg), sizeof(kue_fix_seg));
	if (err) {
		printf("%s: failed to load fixup segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	/* Send trigger command. */
	DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	/*XXXUNCONST*/
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, __UNCONST(kue_trig_seg), sizeof(kue_trig_seg));
	if (err) {
		printf("%s: failed to load trigger segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	usbd_delay_ms(sc->kue_udev, 10);

	/*
	 * Reload device descriptor.
	 * Why? The chip without the firmware loaded returns
	 * one revision code. The chip with the firmware
	 * loaded and running returns a *different* revision
	 * code. This confuses the quirk mechanism, which is
	 * dependent on the revision data.
	 */
	(void)usbd_reload_device_desc(sc->kue_udev);

	DPRINTFN(1,("%s: %s: done\n", USBDEVNAME(sc->kue_dev), __func__));

	/* Reset the adapter. */
	kue_reset(sc);

	return (0);
}
Exemplo n.º 12
0
int
uhub_port_connect(struct uhub_softc *sc, int port, int status, int change)
{
	struct usbd_port *up = &sc->sc_hub->hub->ports[port-1];
	int speed;

	/* We have a connect status change, handle it. */
	usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION);

	/*
	 * If there is already a device on the port the change status
	 * must mean that is has disconnected.  Looking at the
	 * current connect status is not enough to figure this out
	 * since a new unit may have been connected before we handle
	 * the disconnect.
	 */
	if (up->device != NULL) {
		/* Disconnected */
		usbd_detach(up->device, &sc->sc_dev);
		up->device = NULL;
	}

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0)
		return (0);

	/* Connected */
	if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) {
		printf("%s: connected port %d has no power\n", DEVNAME(sc),
		    port);
		return (-1);
	}

	/* Wait for maximum device power up time. */
	usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY);

	/* Reset port, which implies enabling it. */
	if (usbd_reset_port(sc->sc_hub, port)) {
		printf("%s: port %d reset failed\n", DEVNAME(sc), port);
		return (-1);
	}
	/* Get port status again, it might have changed during reset */
	if (usbd_get_port_status(sc->sc_hub, port, &up->status))
		return (-1);

	status = UGETW(up->status.wPortStatus);
	change = UGETW(up->status.wPortChange);
	DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc),
	    port, status, change);

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) {
		DPRINTF("%s: port %d, device disappeared after reset\n",
		    DEVNAME(sc), port);
		return (-1);
	}

	/*
	 * Figure out device speed.  This is a bit tricky because
	 * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit.
	 */
	if ((status & UPS_PORT_POWER) == 0)
		status &= ~UPS_PORT_POWER_SS;

	if (status & UPS_HIGH_SPEED)
		speed = USB_SPEED_HIGH;
	else if (status & UPS_LOW_SPEED)
		speed = USB_SPEED_LOW;
	else {
		/*
		 * If there is no power bit set, it is certainly
		 * a Super Speed device, so use the speed of its
		 * parent hub.
		 */
		if (status & UPS_PORT_POWER)
			speed = USB_SPEED_FULL;
		else
			speed = sc->sc_hub->speed;
	}

	/*
	 * Reduce the speed, otherwise we won't setup the proper
	 * transfer methods.
	 */
	if (speed > sc->sc_hub->speed)
		speed = sc->sc_hub->speed;

	/* Get device info and set its address. */
	if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1,
	    speed, port, up)) {
		/*
		 * The unit refused to accept a new address, or had
		 * some other serious problem.  Since we cannot leave
		 * at 0 we have to disable the port instead.
		 */
		printf("%s: device problem, disabling port %d\n", DEVNAME(sc),
		    port);
		usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE);

		return (-1);
	}

	return (0);
}
Exemplo n.º 13
0
void
uhub_attach(struct device *parent, struct device *self, void *aux)
{
	struct uhub_softc *sc = (struct uhub_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct usbd_device *dev = uaa->device;
	struct usbd_hub *hub = NULL;
	union {
		usb_hub_descriptor_t	hs;
		usb_hub_ss_descriptor_t	ss;
	} hd;
	int p, port, nports, powerdelay;
	struct usbd_interface *iface;
	usb_endpoint_descriptor_t *ed;
	struct usbd_tt *tts = NULL;
	uint8_t ttthink = 0;
	usbd_status err;
#ifdef UHUB_DEBUG
	int nremov;
#endif

	sc->sc_hub = dev;

	err = usbd_set_config_index(dev, 0, 1);
	if (err) {
		DPRINTF("%s: configuration failed, error=%s\n",
			 sc->sc_dev.dv_xname, usbd_errstr(err));
		return;
	}

	if (dev->depth > USB_HUB_MAX_DEPTH) {
		printf("%s: hub depth (%d) exceeded, hub ignored\n",
		       sc->sc_dev.dv_xname, USB_HUB_MAX_DEPTH);
		return;
	}

	/*
	 * Super-Speed hubs need to know their depth to be able to
	 * parse the bits of the route-string that correspond to
	 * their downstream port number.
	 *
	 * This does no apply to root hubs.
	 */
	if (dev->depth != 0 && dev->speed == USB_SPEED_SUPER) {
		if (usbd_set_hub_depth(dev, dev->depth - 1)) {
			printf("%s: unable to set HUB depth\n",
			    sc->sc_dev.dv_xname);
			return;
		}
	}

	/* Get hub descriptor. */
	if (dev->speed == USB_SPEED_SUPER) {
		err = usbd_get_hub_ss_descriptor(dev, &hd.ss, 1);
		nports = hd.ss.bNbrPorts;
		powerdelay = (hd.ss.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
		if (!err && nports > 7)
			usbd_get_hub_ss_descriptor(dev, &hd.ss, nports);
	} else {
		err = usbd_get_hub_descriptor(dev, &hd.hs, 1);
		nports = hd.hs.bNbrPorts;
		powerdelay = (hd.hs.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
		ttthink = UGETW(hd.hs.wHubCharacteristics) & UHD_TT_THINK;
		if (!err && nports > 7)
			usbd_get_hub_descriptor(dev, &hd.hs, nports);
	}

	if (err) {
		DPRINTF("%s: getting hub descriptor failed, error=%s\n",
			 sc->sc_dev.dv_xname, usbd_errstr(err));
		return;
	}

#ifdef UHUB_DEBUG
	for (nremov = 0, port = 1; port <= nports; port++) {
		if (dev->speed == USB_SPEED_SUPER) {
			if (!UHD_NOT_REMOV(&hd.ss, port))
				nremov++;
		} else {
			if (!UHD_NOT_REMOV(&hd.hs, port))
				nremov++;
		}
	}

	printf("%s: %d port%s with %d removable, %s powered",
	       sc->sc_dev.dv_xname, nports, nports != 1 ? "s" : "",
	       nremov, dev->self_powered ? "self" : "bus");

	if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
		printf(", %s transaction translator%s",
		    UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
		    UHUB_IS_SINGLE_TT(sc) ? "" : "s");
	}

	printf("\n");
#endif

	if (nports == 0) {
		printf("%s: no ports, hub ignored\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	hub = malloc(sizeof(*hub), M_USBDEV, M_NOWAIT);
	if (hub == NULL)
		return;
	hub->ports = mallocarray(nports, sizeof(struct usbd_port),
	    M_USBDEV, M_NOWAIT);
	if (hub->ports == NULL) {
		free(hub, M_USBDEV, 0);
		return;
	}
	dev->hub = hub;
	dev->hub->hubsoftc = sc;
	hub->explore = uhub_explore;
	hub->nports = nports;
	hub->powerdelay = powerdelay;
	hub->ttthink = ttthink >> 5;

	if (!dev->self_powered && dev->powersrc->parent != NULL &&
	    !dev->powersrc->parent->self_powered) {
		printf("%s: bus powered hub connected to bus powered hub, "
		       "ignored\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	/* Set up interrupt pipe. */
	err = usbd_device2interface_handle(dev, 0, &iface);
	if (err) {
		printf("%s: no interface handle\n", sc->sc_dev.dv_xname);
		goto bad;
	}
	ed = usbd_interface2endpoint_descriptor(iface, 0);
	if (ed == NULL) {
		printf("%s: no endpoint descriptor\n", sc->sc_dev.dv_xname);
		goto bad;
	}
	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
		printf("%s: bad interrupt endpoint\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	sc->sc_statuslen = (nports + 1 + 7) / 8;
	sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
	if (!sc->sc_statusbuf)
		goto bad;

	err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
		  sc->sc_statuslen, uhub_intr, UHUB_INTR_INTERVAL);
	if (err) {
		printf("%s: cannot open interrupt pipe\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}

	/* Wait with power off for a while. */
	usbd_delay_ms(dev, USB_POWER_DOWN_TIME);

	/*
	 * To have the best chance of success we do things in the exact same
	 * order as Windoze98.  This should not be necessary, but some
	 * devices do not follow the USB specs to the letter.
	 *
	 * These are the events on the bus when a hub is attached:
	 *  Get device and config descriptors (see attach code)
	 *  Get hub descriptor (see above)
	 *  For all ports
	 *     turn on power
	 *     wait for power to become stable
	 * (all below happens in explore code)
	 *  For all ports
	 *     clear C_PORT_CONNECTION
	 *  For all ports
	 *     get port status
	 *     if device connected
	 *        wait 100 ms
	 *        turn on reset
	 *        wait
	 *        clear C_PORT_RESET
	 *        get port status
	 *        proceed with device attachment
	 */

	if (UHUB_IS_HIGH_SPEED(sc)) {
		tts = mallocarray((UHUB_IS_SINGLE_TT(sc) ? 1 : nports),
		    sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
		if (!tts)
			goto bad;
	}
	/* Set up data structures */
	for (p = 0; p < nports; p++) {
		struct usbd_port *up = &hub->ports[p];
		up->device = NULL;
		up->parent = dev;
		up->portno = p + 1;
		if (dev->self_powered)
			/* Self powered hub, give ports maximum current. */
			up->power = USB_MAX_POWER;
		else
			up->power = USB_MIN_POWER;
		up->restartcnt = 0;
		up->reattach = 0;
		if (UHUB_IS_HIGH_SPEED(sc)) {
			up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
			up->tt->hub = hub;
		} else {
			up->tt = NULL;
		}
	}

	for (port = 1; port <= nports; port++) {
		/* Turn the power on. */
		err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
		if (err)
			printf("%s: port %d power on failed, %s\n",
			       sc->sc_dev.dv_xname, port,
			       usbd_errstr(err));
		/* Make sure we check the port status at least once. */
		sc->sc_status |= (1 << port);
	}

	/* Wait for stable power. */
        if (dev->powersrc->parent != NULL)
		usbd_delay_ms(dev, powerdelay + USB_EXTRA_POWER_UP_TIME);

	/* The usual exploration will finish the setup. */

	sc->sc_running = 1;

	return;

 bad:
	if (sc->sc_statusbuf)
		free(sc->sc_statusbuf, M_USBDEV, 0);
	if (hub) {
		if (hub->ports)
			free(hub->ports, M_USBDEV, 0);
		free(hub, M_USBDEV, 0);
	}
	dev->hub = NULL;
}
Exemplo n.º 14
0
/*
 ****************************************************************
 *	Função de "attach"					*
 ****************************************************************
 */
int
uhub_attach (struct device *dev)
{
        struct uhub_softc		*sc;
        struct usb_attach_arg		*uaa  = dev->ivars;
	struct usbd_device		*udev = uaa->device;
	struct usbd_hub			*hub  = NULL;
	struct usb_device_request	req;
	struct usb_hub_descriptor	*hubdesc = NULL;
	struct usbd_interface		*iface;
	struct usb_endpoint_descriptor	*ed;
	int				p, port, nports, nremov, pwrdly, err;

	/*
	 *	Aloca e zera a estrutura "softc"
	 */
	if ((sc = dev->softc = malloc_byte (sizeof (struct uhub_softc))) == NULL)
		return (-1);

	memclr (sc, sizeof (struct uhub_softc));

#if (0)	/*******************************************************/
{
	char				*devinfo;

	if ((devinfo = malloc_byte (1024)) == NULL)
		goto bad;

	memclr (devinfo, 1024);

	usbd_devinfo (udev, USBD_SHOW_INTERFACE_CLASS, devinfo);

	device_set_desc_copy (dev, devinfo);

	free_byte (devinfo);
}
#endif	/*******************************************************/

	sc->sc_hub = udev;
	sc->sc_dev = dev;

	if (err = usbd_set_config_index (udev, 0, 1))
	{
		printf ("uhub_attach (%s): erro na configuração (%s)\n", dev->nameunit, usbd_errstr (err));
		goto bad;
	}

	if (udev->depth > USB_HUB_MAX_DEPTH)
	{
		printf
		(	"uhub_attach (%s): profundidade máxima excedida (%d > %d), \"hub\" ignorado\n",
			dev->nameunit, udev->depth, USB_HUB_MAX_DEPTH
		);
		goto bad;
	}

	/* Get hub descriptor */

	if ((hubdesc = malloc_byte (sizeof (struct usb_hub_descriptor))) == NULL)
		{ err = USBD_NOMEM; goto bad; }

	req.bmRequestType	= UT_READ_CLASS_DEVICE;
	req.bRequest		= UR_GET_DESCRIPTOR;

	USETW2 (req.wValue, (udev->address > 1 ? UDESC_HUB : 0), 0);
	USETW  (req.wIndex, 0);
	USETW  (req.wLength, USB_HUB_DESCRIPTOR_SIZE);

	err = usbd_do_request (udev, &req, hubdesc);

	nports = hubdesc->bNbrPorts;

	if (err == 0 && nports > 7)
	{
		USETW (req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports + 1) / 8);

		err = usbd_do_request (udev, &req, hubdesc);
	}

	if (err)
	{
		printf
		(	"uhub_attach (%s): erro ao ler descritor do hub (%s)\n",
			dev->nameunit, usbd_errstr (err)
		);

		goto bad;
	}

	for (nremov = 0, port = 1; port <= nports; port++)
	{
		if (!UHD_NOT_REMOV (hubdesc, port))
			nremov++;
	}

	if (nports == 0)
		{ printf ("%s: hub sem portas ignorado\n", dev->nameunit); goto bad; }

	printf
	(	"%s: %d porta%s, %d removíve%s, %s energizadas\n",
		dev->nameunit,
		nports, nports != 1 ? "s" : "",
		nremov, nremov != 1 ? "is" : "l",
		udev->self_powered ? "auto" : "bus"
	);

	if ((hub = malloc_byte (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port))) == NULL)
		goto bad;

	memclr (hub, (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port)));

	udev->hub		= hub;
	udev->hub->hubsoftc	= sc;
	hub->explore		= uhub_explore;
	hub->hubdesc		= *hubdesc;

	free_byte (hubdesc); hubdesc = NULL;

#ifdef	USB_MSG
	printf
	(	"uhub_attach: selfpowered=%d, parent=%p, parent->selfpowered=%d\n",
		 dev->self_powered, dev->powersrc->parent,
		 dev->powersrc->parent ? dev->powersrc->parent->self_powered : 0
	);
#endif	USB_MSG

	if (!udev->self_powered && udev->powersrc->parent != NULL && !udev->powersrc->parent->self_powered)
	{
		printf
		(	"uhub_attach (%s): bus powered hub connected to bus powered hub, ignored\n",
			dev->nameunit
		);
		goto bad;
	}

	/* Set up interrupt pipe */

	if (usbd_device2interface_handle (udev, 0, &iface))
	{
		printf ("uhub_attach (%s): no interface handle\n", dev->nameunit);
		goto bad;
	}

	if ((ed = usbd_interface2endpoint_descriptor (iface, 0)) == NULL)
	{
		printf ("uhub_attach (%s): no endpoint descriptor\n", dev->nameunit);
		goto bad;
	}

	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT)
	{
		printf ("uhub_attach (%s): bad interrupt endpoint\n", dev->nameunit);
		goto bad;
	}

	if
	(	usbd_open_pipe_intr
		(	iface, ed->bEndpointAddress,
			USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, 
			sizeof (sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL
		)
	)
	{
		printf ("uhub_attach (%s): cannot open interrupt pipe\n", dev->nameunit);
		goto bad;
	}

	/* Wait with power off for a while */

	usbd_delay_ms (udev, USB_POWER_DOWN_TIME);

	/*
	 * To have the best chance of success we do things in the exact same
	 * order as Windoze98.  This should not be necessary, but some
	 * devices do not follow the USB specs to the letter.
	 *
	 * These are the events on the bus when a hub is attached:
	 *  Get device and config descriptors (see attach code)
	 *  Get hub descriptor (see above)
	 *  For all ports
	 *     turn on power
	 *     wait for power to become stable
	 * (all below happens in explore code)
	 *  For all ports
	 *     clear C_PORT_CONNECTION
	 *  For all ports
	 *     get port status
	 *     if device connected
	 *        wait 100 ms
	 *        turn on reset
	 *        wait
	 *        clear C_PORT_RESET
	 *        get port status
	 *        proceed with device attachment
	 */

	/* Set up data structures */

	for (p = 0; p < nports; p++)
	{
		struct usbd_port	*up = &hub->ports[p];

		up->device = NULL;
		up->parent = udev;
		up->portno = p+1;

		if (udev->self_powered) /* Self powered hub, give ports maximum current */
			up->power = USB_MAX_POWER;
		else
			up->power = USB_MIN_POWER;

		up->restartcnt = 0;
	}

	/* XXX should check for none, individual, or ganged power? */

	pwrdly = udev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR + USB_EXTRA_POWER_UP_TIME;

	for (port = 1; port <= nports; port++)
	{
		/* Turn the power on */

		if (err = usbd_set_port_feature (udev, port, UHF_PORT_POWER))
		{
			printf
			(	"uhub_attach (%s): port %d power on failed, %s\n", 
				dev->nameunit, port, usbd_errstr (err)
			);
		}

#ifdef	USB_MSG
		printf ("uhub_attach: turn on port %d power\n", port);
#endif	USB_MSG

		/* Wait for stable power */

		usbd_delay_ms (udev, pwrdly);
	}

	/* The usual exploration will finish the setup */

	sc->sc_running = 1;

	return (0);

	/*
	 *	Em caso de erro, ...
	 */
    bad:
	if (hubdesc != NULL)
		free_byte (hubdesc);

	if (hub != NULL)
		free_byte (hub);

	udev->hub = NULL;

	free_byte (sc);	dev->softc = NULL;

	return (-1);

}	/* end uhub_attach */
Exemplo n.º 15
0
/*
 * Called when a new device has been put in the powered state,
 * but not yet in the addressed state.
 * Get initial descriptor, set the address, get full descriptor,
 * and attach a driver.
 */
usbd_status
usbd_new_device(device_t parent, struct usbd_bus* bus, int depth,
                int speed, int port, struct usbd_port *up)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	struct usbd_device *dev, *adev;
	struct usbd_device *hub;
	usb_device_descriptor_t *dd;
	usb_port_status_t ps;
	usbd_status err;
	int addr;
	int i;
	int p;

	DPRINTF("bus=%p port=%d depth=%d speed=%d", bus, port, depth, speed);

	if (bus->ub_methods->ubm_newdev != NULL)
		return (bus->ub_methods->ubm_newdev)(parent, bus, depth, speed,
		    port, up);

	addr = usbd_getnewaddr(bus);
	if (addr < 0) {
		printf("%s: No free USB addresses, new device ignored.\n",
		       device_xname(bus->ub_usbctl));
		return USBD_NO_ADDR;
	}

	dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
	if (dev == NULL)
		return USBD_NOMEM;

	dev->ud_bus = bus;

	/* Set up default endpoint handle. */
	dev->ud_ep0.ue_edesc = &dev->ud_ep0desc;

	/* Set up default endpoint descriptor. */
	dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
	dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
	dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
	dev->ud_ep0desc.bmAttributes = UE_CONTROL;
	/*
	 * temporary, will be fixed after first descriptor fetch
	 * (which uses 64 bytes so it shouldn't be less),
	 * highspeed devices must support 64 byte packets anyway
	 */
	if (speed == USB_SPEED_HIGH || speed == USB_SPEED_FULL)
		USETW(dev->ud_ep0desc.wMaxPacketSize, 64);
	else
		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);

	dev->ud_ep0desc.bInterval = 0;

	/* doesn't matter, just don't leave it uninitialized */
	dev->ud_ep0.ue_toggle = 0;

	dev->ud_quirks = &usbd_no_quirk;
	dev->ud_addr = USB_START_ADDR;
	dev->ud_ddesc.bMaxPacketSize = 0;
	dev->ud_depth = depth;
	dev->ud_powersrc = up;
	dev->ud_myhub = up->up_parent;

	up->up_dev = dev;

	/* Locate port on upstream high speed hub */
	for (adev = dev, hub = up->up_parent;
	     hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
	     adev = hub, hub = hub->ud_myhub)
		;
	if (hub) {
		for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
			if (hub->ud_hub->uh_ports[p].up_dev == adev) {
				dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
				goto found;
			}
		}
		panic("usbd_new_device: cannot find HS port");
	found:
		DPRINTFN(1, "high speed port %d", p, 0, 0, 0);
	} else {
		dev->ud_myhsport = NULL;
	}
	dev->ud_speed = speed;
	dev->ud_langid = USBD_NOLANG;
	dev->ud_cookie.cookie = ++usb_cookie_no;

	/* Establish the default pipe. */
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
			      &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		usbd_remove_device(dev, up);
		return err;
	}

	dd = &dev->ud_ddesc;
	/* Try a few times in case the device is slow (i.e. outside specs.) */
	for (i = 0; i < 10; i++) {
		/* Get the first 8 bytes of the device descriptor. */
		err = usbd_get_initial_ddesc(dev, dd);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
		if ((i & 3) == 3)
			usbd_reset_port(up->up_parent, port, &ps);
	}
	if (err) {
		DPRINTF("addr=%d, getting first desc failed: %d", addr, err,
		    0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Windows resets the port here, do likewise */
	if (up->up_parent)
		usbd_reset_port(up->up_parent, port, &ps);

	if (speed == USB_SPEED_HIGH) {
		/* Max packet size must be 64 (sec 5.5.3). */
		if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
#ifdef DIAGNOSTIC
			printf("usbd_new_device: addr=%d bad max packet "
			    "size=%d. adjusting to %d.\n",
			    addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET);
#endif
			dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
		}
	}

	DPRINTF("adding unit addr=%d, rev=%02x, class=%d, subclass=%d", addr,
	    UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass);
	DPRINTF("protocol=%d, maxpacket=%d, len=%d, speed=%d",
	    dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, dev->ud_speed);

	if (dd->bDescriptorType != UDESC_DEVICE) {
		/* Illegal device descriptor */
		DPRINTF("illegal descriptor %d", dd->bDescriptorType, 0, 0, 0);
		usbd_remove_device(dev, up);
		return USBD_INVAL;
	}

	if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
		DPRINTF("bad length %d", dd->bLength, 0, 0, 0);
		usbd_remove_device(dev, up);
		return USBD_INVAL;
	}

	USETW(dev->ud_ep0desc.wMaxPacketSize, dd->bMaxPacketSize);

	/* Re-establish the default pipe with the new MPS. */
	usbd_kill_pipe(dev->ud_pipe0);
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
	    &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		DPRINTF("setup default pipe failed err %d", err, 0, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Set the address */
	DPRINTFN(5, "setting device address=%d", addr, 0, 0, 0);
	err = usbd_set_address(dev, addr);
	if (err) {
		DPRINTF("set address %d failed, err = %d", addr, err, 0, 0);
		err = USBD_SET_ADDR_FAILED;
		usbd_remove_device(dev, up);
		return err;
	}

	/* Allow device time to set new address */
	usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
	dev->ud_addr = addr;	/* new device address now */
	bus->ub_devices[addr] = dev;

	/* Re-establish the default pipe with the new address. */
	usbd_kill_pipe(dev->ud_pipe0);
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
	    &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		DPRINTF("setup default pipe failed, err = %d", err, 0, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	err = usbd_reload_device_desc(dev);
	if (err) {
		DPRINTF("addr=%d, getting full desc failed, err = %d", addr,
		    err, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Assume 100mA bus powered for now. Changed when configured. */
	dev->ud_power = USB_MIN_POWER;
	dev->ud_selfpowered = 0;

	DPRINTF("new dev (addr %d), dev=%p, parent=%p", addr, dev, parent, 0);

	usbd_get_device_strings(dev);

	usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);

	if (port == 0) { /* root hub */
		KASSERT(addr == 1);
		usbd_attach_roothub(parent, dev);
		return USBD_NORMAL_COMPLETION;
	}

	err = usbd_probe_and_attach(parent, dev, port, addr);
	if (err) {
		usbd_remove_device(dev, up);
		return err;
	}

	return USBD_NORMAL_COMPLETION;
}
Exemplo n.º 16
0
usbd_status
usbd_set_config_index(usbd_device_handle dev, int index, int msg)
{
	usb_status_t ds;
	usb_config_descriptor_t cd, *cdp;
	usbd_status err;
	int i, ifcidx, nifc, len, selfpowered, power;

	DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));

	if (dev->config != USB_UNCONFIG_NO) {
		nifc = dev->cdesc->bNumInterface;

		/* Check that all interfaces are idle */
		for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
			if (LIST_EMPTY(&dev->ifaces[ifcidx].pipes))
				continue;
			DPRINTF(("usbd_set_config_index: open pipes exist\n"));
			return (USBD_IN_USE);
		}

		DPRINTF(("usbd_set_config_index: free old config\n"));
		/* Free all configuration data structures. */
		for (ifcidx = 0; ifcidx < nifc; ifcidx++)
			usbd_free_iface_data(dev, ifcidx);
		kfree(dev->ifaces, M_USB);
		kfree(dev->cdesc, M_USB);
		dev->ifaces = NULL;
		dev->cdesc = NULL;
		dev->config = USB_UNCONFIG_NO;
	}

	if (index == USB_UNCONFIG_INDEX) {
		/* We are unconfiguring the device, so leave unallocated. */
		DPRINTF(("usbd_set_config_index: set config 0\n"));
		err = usbd_set_config(dev, USB_UNCONFIG_NO);
		if (err)
			DPRINTF(("usbd_set_config_index: setting config=0 "
				 "failed, error=%s\n", usbd_errstr(err)));
		return (err);
	}

	/* Get the short descriptor. */
	err = usbd_get_config_desc(dev, index, &cd);
	if (err)
		return (err);
	len = UGETW(cd.wTotalLength);
	cdp = kmalloc(len, M_USB, M_INTWAIT);
	/* Get the full descriptor.  Try a few times for slow devices. */
	for (i = 0; i < 3; i++) {
		err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
	}
	if (err)
		goto bad;
	if (cdp->bDescriptorType != UDESC_CONFIG) {
		DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
			     cdp->bDescriptorType));
		err = USBD_INVAL;
		goto bad;
	}

	/* Figure out if the device is self or bus powered. */
	selfpowered = 0;
	if (!(dev->quirks->uq_flags & UQ_BUS_POWERED) &&
	    (cdp->bmAttributes & UC_SELF_POWERED)) {
		/* May be self powered. */
		if (cdp->bmAttributes & UC_BUS_POWERED) {
			/* Must ask device. */
			if (dev->quirks->uq_flags & UQ_POWER_CLAIM) {
				/*
				 * Hub claims to be self powered, but isn't.
				 * It seems that the power status can be
				 * determined by the hub characteristics.
				 */
				usb_hub_descriptor_t hd;
				usb_device_request_t req;
				req.bmRequestType = UT_READ_CLASS_DEVICE;
				req.bRequest = UR_GET_DESCRIPTOR;
				USETW(req.wValue, 0);
				USETW(req.wIndex, 0);
				USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
				err = usbd_do_request(dev, &req, &hd);
				if (!err &&
				    (UGETW(hd.wHubCharacteristics) &
				     UHD_PWR_INDIVIDUAL))
					selfpowered = 1;
				DPRINTF(("usbd_set_config_index: charac=0x%04x"
				    ", error=%s\n",
				    UGETW(hd.wHubCharacteristics),
				    usbd_errstr(err)));
			} else {
				err = usbd_get_device_status(dev, &ds);
				if (!err &&
				    (UGETW(ds.wStatus) & UDS_SELF_POWERED))
					selfpowered = 1;
				DPRINTF(("usbd_set_config_index: status=0x%04x"
				    ", error=%s\n",
				    UGETW(ds.wStatus), usbd_errstr(err)));
			}
		} else
			selfpowered = 1;
	}
	DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, "
		 "selfpowered=%d, power=%d\n",
		 cdp->bConfigurationValue, dev->address, cdp->bmAttributes,
		 selfpowered, cdp->bMaxPower * 2));

	/* Check if we have enough power. */
#ifdef USB_DEBUG
	if (dev->powersrc == NULL) {
		DPRINTF(("usbd_set_config_index: No power source?\n"));
		return (USBD_IOERROR);
	}
#endif
	power = cdp->bMaxPower * 2;
	if (power > dev->powersrc->power) {
		DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power));
		/* XXX print nicer message. */
		if (msg)
			kprintf("%s: device addr %d (config %d) exceeds power "
				 "budget, %d mA > %d mA\n",
			       device_get_nameunit(dev->bus->bdev), dev->address,
			       cdp->bConfigurationValue,
			       power, dev->powersrc->power);
		err = USBD_NO_POWER;
		goto bad;
	}
	dev->power = power;
	dev->self_powered = selfpowered;

	/* Set the actual configuration value. */
	DPRINTF(("usbd_set_config_index: set config %d\n",
		 cdp->bConfigurationValue));
	err = usbd_set_config(dev, cdp->bConfigurationValue);
	if (err) {
		DPRINTF(("usbd_set_config_index: setting config=%d failed, "
			 "error=%s\n",
			 cdp->bConfigurationValue, usbd_errstr(err)));
		goto bad;
	}

	/* Allocate and fill interface data. */
	nifc = cdp->bNumInterface;
	dev->ifaces = kmalloc(nifc * sizeof(struct usbd_interface),
			     M_USB, M_INTWAIT);
	DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));
	dev->cdesc = cdp;
	dev->config = cdp->bConfigurationValue;
	for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
		err = usbd_fill_iface_data(dev, ifcidx, 0);
		if (err) {
			while (--ifcidx >= 0)
				usbd_free_iface_data(dev, ifcidx);
			goto bad;
		}
	}

	return (USBD_NORMAL_COMPLETION);

 bad:
	kfree(cdp, M_USB);
	return (err);
}
Exemplo n.º 17
0
void
ukbd_attach(struct device *parent, struct device *self, void *aux)
{
	struct ukbd_softc *sc = (struct ukbd_softc *)self;
	struct hidkbd *kbd = &sc->sc_kbd;
	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
	struct usb_hid_descriptor *hid;
	u_int32_t qflags;
	int dlen, repid;
	void *desc;
	kbd_t layout = (kbd_t)-1;

	sc->sc_hdev.sc_intr = ukbd_intr;
	sc->sc_hdev.sc_parent = uha->parent;
	sc->sc_hdev.sc_udev = uha->uaa->device;
	sc->sc_hdev.sc_report_id = uha->reportid;

	uhidev_get_report_desc(uha->parent, &desc, &dlen);
	repid = uha->reportid;
	sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid);
	sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid);
	sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid);

	qflags = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags;
	if (hidkbd_attach(self, kbd, 1, qflags, repid, desc, dlen) != 0)
		return;

	if (uha->uaa->vendor == USB_VENDOR_APPLE) {
		int iso = 0;

		if ((uha->uaa->product == USB_PRODUCT_APPLE_FOUNTAIN_ISO) ||
 		    (uha->uaa->product == USB_PRODUCT_APPLE_GEYSER_ISO))
 		    	iso = 1;

		if (hid_locate(desc, dlen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY),
		    uha->reportid, hid_input, &sc->sc_apple_fn, &qflags)) {
			if (qflags & HIO_VARIABLE) {
				if (iso)
					sc->sc_munge = ukbd_apple_iso_munge;
				else
					sc->sc_munge = ukbd_apple_munge;
			}
		}
	}

	if (uha->uaa->vendor == USB_VENDOR_TOPRE &&
	    uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) {
		/* ignore country code on purpose */
	} else {
		hid = usbd_get_hid_descriptor(uha->uaa->iface);

		if (hid->bCountryCode <= HCC_MAX)
			layout = ukbd_countrylayout[hid->bCountryCode];
#ifdef DIAGNOSTIC
		if (hid->bCountryCode != 0)
			printf(", country code %d", hid->bCountryCode);
#endif
	}
	if (layout == (kbd_t)-1) {
#ifdef UKBD_LAYOUT
		layout = UKBD_LAYOUT;
#else
		layout = KB_US | KB_DEFAULT;
#endif
	}

	printf("\n");

#ifdef __loongson__
	if (uha->uaa->vendor == USB_VENDOR_CYPRESS &&
	    uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK)
		sc->sc_munge = ukbd_gdium_munge;
#endif

	if (kbd->sc_console_keyboard) {
		extern struct wskbd_mapdata ukbd_keymapdata;

		DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
		ukbd_keymapdata.layout = layout;
		wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
		ukbd_enable(sc, 1);
	}

	/* Flash the leds; no real purpose, just shows we're alive. */
	ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM |
		          WSKBD_LED_CAPS | WSKBD_LED_COMPOSE);
	usbd_delay_ms(sc->sc_hdev.sc_udev, 400);
	ukbd_set_leds(sc, 0);

	hidkbd_attach_wskbd(kbd, layout, &ukbd_accessops);
}
Exemplo n.º 18
0
usbd_status
uhub_explore(usbd_device_handle dev)
{
	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
	device_t self = dev->hub->hubdev;
	struct uhub_softc *sc = device_get_softc(self);
	struct usbd_port *up;
	usbd_status err;
	int speed;
	int port;
	int change, status;

	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));

	if (!sc->sc_running)
		return (USBD_NOT_STARTED);

	/* Ignore hubs that are too deep. */
	if (dev->depth > USB_HUB_MAX_DEPTH)
		return (USBD_TOO_DEEP);

	for(port = 1; port <= hd->bNbrPorts; port++) {
		up = &dev->hub->ports[port-1];
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n",
			    device_get_nameunit(self), port, status, change));
		if (change & UPS_C_PORT_ENABLED) {
			DPRINTF(("uhub_explore: C_PORT_ENABLED 0x%x\n", change));
			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
			if (change & UPS_C_CONNECT_STATUS) {
				/* Ignore the port error if the device
				   vanished. */
			} else if (status & UPS_PORT_ENABLED) {
				device_printf(self,
				    "illegal enable change, port %d\n", port);
			} else {
				/* Port error condition. */
				if (up->restartcnt) /* no message first time */
					device_printf(self,
					    "port error, restarting "
					    "port %d\n", port);

				if (up->restartcnt++ < USBD_RESTART_MAX)
					goto disco;
				else
					device_printf(self,
					    "port error, giving up "
					    "port %d\n", port);
			}
		}
		if (!(change & UPS_C_CONNECT_STATUS)) {
			DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
				    "STATUS\n", port));
			/* No status change, just do recursive explore. */
			if (up->device != NULL && up->device->hub != NULL)
				up->device->hub->explore(up->device);
#if 0 && defined(DIAGNOSTIC)
			if (up->device == NULL &&
			    (status & UPS_CURRENT_CONNECT_STATUS))
				device_printf(self,
				    "connected, no device\n");
#endif
			continue;
		}

		/* We have a connect status change, handle it. */

		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
			 dev->address, port));
		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
		/*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/
		/*
		 * If there is already a device on the port the change status
		 * must mean that is has disconnected.  Looking at the
		 * current connect status is not enough to figure this out
		 * since a new unit may have been connected before we handle
		 * the disconnect.
		 */
	disco:
		if (up->device != NULL) {
			/* Disconnected */
			DPRINTF(("uhub_explore: device addr=%d disappeared "
				 "on port %d\n", up->device->address, port));
			usb_disconnect_port(up, self);
			usbd_clear_port_feature(dev, port,
						UHF_C_PORT_CONNECTION);
		}
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
			DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
				    "_STATUS\n", port));
			continue;
		}

		/* Connected */

		if (!(status & UPS_PORT_POWER))
			device_printf(self,
			    "strange, connected port %d has no power\n",
			    port);

		/* Wait for maximum device power up time. */
		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);

		/* Reset port, which implies enabling it. */
		if (usbd_reset_port(dev, port, &up->status)) {
			device_printf(self,
			    "port %d reset failed\n", port);
			continue;
		}
		/* Get port status again, it might have changed during reset */
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
#ifdef DIAGNOSTIC
			device_printf(self,
			    "port %d, device disappeared after reset\n",
			    port);
#endif
			continue;
		}

#if 0
		if (UHUB_IS_HIGH_SPEED(sc) && !(status & UPS_HIGH_SPEED)) {
			device_printf(self,
			    "port %d, transaction translation not "
			    "implemented, low/full speed device ignored\n",
			    port);
			continue;
		}
#endif

		/* Figure out device speed */
		if (status & UPS_HIGH_SPEED)
			speed = USB_SPEED_HIGH;
		else if (status & UPS_LOW_SPEED)
			speed = USB_SPEED_LOW;
		else
			speed = USB_SPEED_FULL;
		/* Get device info and set its address. */
		err = usbd_new_device(self, dev->bus,
				      dev->depth + 1, speed, port, up);
		/* XXX retry a few times? */
		if (err) {
			DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
				     "error=%s\n", usbd_errstr(err)));
			/* Avoid addressing problems by disabling. */
			/* usbd_reset_port(dev, port, &up->status); */

			/*
			 * The unit refused to accept a new address, or had
			 * some other serious problem.  Since we cannot leave
			 * at 0 we have to disable the port instead.
			 */
			device_printf(self,
			    "device problem (%s), disabling port %d\n",
			    usbd_errstr(err), port);
			usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
		} else {
			/* The port set up succeeded, reset error count. */
			up->restartcnt = 0;

			if (up->device->hub)
				up->device->hub->explore(up->device);
		}
	}
	return (USBD_NORMAL_COMPLETION);
}
Exemplo n.º 19
0
void
ukbd_attach(device_t parent, device_t self, void *aux)
{
	struct ukbd_softc *sc = device_private(self);
	struct uhidev_attach_arg *uha = aux;
	u_int32_t qflags;
	const char *parseerr;
#if defined(__NetBSD__)
	struct wskbddev_attach_args a;
#else
	int i;
#endif

	sc->sc_hdev.sc_dev = self;
	sc->sc_hdev.sc_intr = ukbd_intr;
	sc->sc_hdev.sc_parent = uha->parent;
	sc->sc_hdev.sc_report_id = uha->reportid;

	if (!pmf_device_register(self, NULL, NULL)) {
		aprint_normal("\n");
		aprint_error_dev(self, "couldn't establish power handler\n");
	}

	parseerr = ukbd_parse_desc(sc);
	if (parseerr != NULL) {
		aprint_normal("\n");
		aprint_error_dev(self, "attach failed, %s\n", parseerr);
		USB_ATTACH_ERROR_RETURN;
	}

#ifdef DIAGNOSTIC
	aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod,
	       sc->sc_nkeycode);
#endif
	aprint_normal("\n");

	qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
	sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0;

	/*
	 * Remember if we're the console keyboard.
	 *
	 * XXX This always picks the first keyboard on the
	 * first USB bus, but what else can we really do?
	 */
	if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
		/* Don't let any other keyboard have it. */
		ukbd_is_console = 0;
	}

	if (sc->sc_console_keyboard) {
		DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
		wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
		ukbd_enable(sc, 1);
	}

	a.console = sc->sc_console_keyboard;

	a.keymap = &ukbd_keymapdata;

	a.accessops = &ukbd_accessops;
	a.accesscookie = sc;

#ifdef UKBD_REPEAT
	usb_callout_init(sc->sc_rawrepeat_ch);
#endif

	usb_callout_init(sc->sc_delay);

	/* Flash the leds; no real purpose, just shows we're alive. */
	ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
	usbd_delay_ms(uha->parent->sc_udev, 400);
	ukbd_set_leds(sc, 0);

	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);

	USB_ATTACH_SUCCESS_RETURN;
}
Exemplo n.º 20
0
usbd_status
usbd_set_config_index(struct usbd_device *dev, int index, int msg)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	usb_config_descriptor_t cd, *cdp;
	usb_bos_descriptor_t *bdp = NULL;
	usbd_status err;
	int i, ifcidx, nifc, len, selfpowered, power;

	DPRINTFN(5, "dev=%p index=%d", dev, index, 0, 0);

	if (index >= dev->ud_ddesc.bNumConfigurations &&
	    index != USB_UNCONFIG_INDEX) {
		/* panic? */
		printf("usbd_set_config_index: illegal index\n");
		return USBD_INVAL;
	}

	/* XXX check that all interfaces are idle */
	if (dev->ud_config != USB_UNCONFIG_NO) {
		DPRINTF("free old config", 0, 0, 0, 0);
		/* Free all configuration data structures. */
		nifc = dev->ud_cdesc->bNumInterface;
		for (ifcidx = 0; ifcidx < nifc; ifcidx++)
			usbd_free_iface_data(dev, ifcidx);
		kmem_free(dev->ud_ifaces, nifc * sizeof(struct usbd_interface));
		kmem_free(dev->ud_cdesc, UGETW(dev->ud_cdesc->wTotalLength));
		if (dev->ud_bdesc != NULL)
			kmem_free(dev->ud_bdesc,
			    UGETW(dev->ud_bdesc->wTotalLength));
		dev->ud_ifaces = NULL;
		dev->ud_cdesc = NULL;
		dev->ud_bdesc = NULL;
		dev->ud_config = USB_UNCONFIG_NO;
	}

	if (index == USB_UNCONFIG_INDEX) {
		/* We are unconfiguring the device, so leave unallocated. */
		DPRINTF("set config 0", 0, 0, 0, 0);
		err = usbd_set_config(dev, USB_UNCONFIG_NO);
		if (err) {
			DPRINTF("setting config=0 failed, err = %d", err,
			    0, 0, 0);
		}
		return err;
	}

	/* Get the short descriptor. */
	err = usbd_get_config_desc(dev, index, &cd);
	if (err) {
		DPRINTF("get_config_desc=%d", err, 0, 0, 0);
		return err;
	}
	len = UGETW(cd.wTotalLength);
	cdp = kmem_alloc(len, KM_SLEEP);
	if (cdp == NULL)
		return USBD_NOMEM;

	/* Get the full descriptor.  Try a few times for slow devices. */
	for (i = 0; i < 3; i++) {
		err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
	}
	if (err) {
		DPRINTF("get_desc=%d", err, 0, 0, 0);
		goto bad;
	}
	if (cdp->bDescriptorType != UDESC_CONFIG) {
		DPRINTF("bad desc %d", cdp->bDescriptorType, 0, 0, 0);
		err = USBD_INVAL;
		goto bad;
	}

	if (USB_IS_SS(dev->ud_speed)) {
		usb_bos_descriptor_t bd;

		/* get short bos desc */
		err = usbd_get_bos_desc(dev, index, &bd);
		if (!err) {
			int blen = UGETW(bd.wTotalLength);
			bdp = kmem_alloc(blen, KM_SLEEP);
			if (bdp == NULL) {
				err = USBD_NOMEM;
				goto bad;
			}

			/* Get the full desc */
			for (i = 0; i < 3; i++) {
				err = usbd_get_desc(dev, UDESC_BOS, index, blen,
				    bdp);
				if (!err)
					break;
				usbd_delay_ms(dev, 200);
			}
			if (err || bdp->bDescriptorType != UDESC_BOS) {
				DPRINTF("error %d or bad desc %d", err,
				    bdp->bDescriptorType, 0, 0);
				kmem_free(bdp, blen);
				bdp = NULL;
			}
		}
	}
	dev->ud_bdesc = bdp;

	/*
	 * Figure out if the device is self or bus powered.
	 */
#if 0 /* XXX various devices don't report the power state correctly */
	selfpowered = 0;
	err = usbd_get_device_status(dev, &ds);
	if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED))
		selfpowered = 1;
#endif
	/*
	 * Use the power state in the configuration we are going
	 * to set. This doesn't necessarily reflect the actual
	 * power state of the device; the driver can control this
	 * by choosing the appropriate configuration.
	 */
	selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED);

	DPRINTF("addr %d cno=%d attr=0x%02x, selfpowered=%d",
	    dev->ud_addr, cdp->bConfigurationValue, cdp->bmAttributes,
	    selfpowered);
	DPRINTF("max power=%d", cdp->bMaxPower * 2, 0, 0, 0);

	/* Check if we have enough power. */
#if 0 /* this is a no-op, see above */
	if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) {
		if (msg)
			printf("%s: device addr %d (config %d): "
				 "can't set self powered configuration\n",
			       device_xname(dev->ud_bus->bdev), dev->ud_addr,
			       cdp->bConfigurationValue);
		err = USBD_NO_POWER;
		goto bad;
	}
#endif
#ifdef USB_DEBUG
	if (dev->ud_powersrc == NULL) {
		DPRINTF("No power source?", 0, 0, 0, 0);
		err = USBD_IOERROR;
		goto bad;
	}
#endif
	power = cdp->bMaxPower * 2;
	if (power > dev->ud_powersrc->up_power) {
		DPRINTF("power exceeded %d %d", power, dev->ud_powersrc->up_power,
		    0, 0);
		/* XXX print nicer message. */
		if (msg)
			printf("%s: device addr %d (config %d) exceeds power "
				 "budget, %d mA > %d mA\n",
			       device_xname(dev->ud_bus->ub_usbctl), dev->ud_addr,
			       cdp->bConfigurationValue,
			       power, dev->ud_powersrc->up_power);
		err = USBD_NO_POWER;
		goto bad;
	}
	dev->ud_power = power;
	dev->ud_selfpowered = selfpowered;

	/* Set the actual configuration value. */
	DPRINTF("set config %d", cdp->bConfigurationValue, 0, 0, 0);
	err = usbd_set_config(dev, cdp->bConfigurationValue);
	if (err) {
		DPRINTF("setting config=%d failed, error=%d",
		    cdp->bConfigurationValue, err, 0, 0);
		goto bad;
	}

	/* Allocate and fill interface data. */
	nifc = cdp->bNumInterface;
	dev->ud_ifaces = kmem_alloc(nifc * sizeof(struct usbd_interface),
	    KM_SLEEP);
	if (dev->ud_ifaces == NULL) {
		err = USBD_NOMEM;
		goto bad;
	}
	DPRINTFN(5, "dev=%p cdesc=%p", dev, cdp, 0, 0);
	dev->ud_cdesc = cdp;
	dev->ud_config = cdp->bConfigurationValue;
	for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
		err = usbd_fill_iface_data(dev, ifcidx, 0);
		if (err) {
			while (--ifcidx >= 0)
				usbd_free_iface_data(dev, ifcidx);
			goto bad;
		}
	}

	return USBD_NORMAL_COMPLETION;

 bad:
	kmem_free(cdp, len);
	if (bdp != NULL) {
		kmem_free(bdp, UGETW(bdp->wTotalLength));
		dev->ud_bdesc = NULL;
	}
	return err;
}
Exemplo n.º 21
0
/*
 * Called when a new device has been put in the powered state,
 * but not yet in the addressed state.
 * Get initial descriptor, set the address, get full descriptor,
 * and attach a driver.
 */
usbd_status
usbd_new_device(device_t parent, usbd_bus_handle bus, int depth,
		int speed, int port, struct usbd_port *up)
{
	usbd_device_handle dev, adev;
	struct usbd_device *hub;
	usb_device_descriptor_t *dd;
	usb_port_status_t ps;
	usbd_status err;
	int addr;
	int i;
	int p;

	DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
		 bus, port, depth, speed));
	addr = usbd_getnewaddr(bus);
	if (addr < 0) {
		kprintf("%s: No free USB addresses, new device ignored.\n",
		       device_get_nameunit(bus->bdev));
		return (USBD_NO_ADDR);
	}

	dev = kmalloc(sizeof *dev, M_USB, M_INTWAIT | M_ZERO);
	dev->bus = bus;

	/* Set up default endpoint handle. */
	dev->def_ep.edesc = &dev->def_ep_desc;

	/* Set up default endpoint descriptor. */
	dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
	dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
	dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
	dev->def_ep_desc.bmAttributes = UE_CONTROL;
	USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
	dev->def_ep_desc.bInterval = 0;

	dev->quirks = &usbd_no_quirk;
	dev->address = USB_START_ADDR;
	dev->ddesc.bMaxPacketSize = 0;
	dev->depth = depth;
	dev->powersrc = up;
	dev->myhub = up->parent;

	up->device = dev;

	/* Locate port on upstream high speed hub */
	for (adev = dev, hub = up->parent;
	     hub != NULL && hub->speed != USB_SPEED_HIGH;
	     adev = hub, hub = hub->myhub)
		;
	if (hub) {
		for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
			if (hub->hub->ports[p].device == adev) {
				dev->myhsport = &hub->hub->ports[p];
				goto found;
			}
		}
		panic("usbd_new_device: cannot find HS port\n");
	found:
		DPRINTFN(1,("usbd_new_device: high speed port %d\n", p));
	} else {
		dev->myhsport = NULL;
	}
	dev->speed = speed;
	dev->langid = USBD_NOLANG;
	dev->cookie.cookie = ++usb_cookie_no;

	/* Establish the default pipe. */
	err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
			      &dev->default_pipe);
	if (err) {
		usbd_remove_device(dev, up);
		return (err);
	}

	/* Set the address.  Do this early; some devices need that. */
	/* Try a few times in case the device is slow (i.e. outside specs.) */
	DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr));
	for (i = 0; i < 5; i++) {
		err = usbd_set_address(dev, addr);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
		if ((i & 3) == 3) {
			DPRINTFN(-1,("usb_new_device: set address %d "
			    "failed - trying a port reset\n", addr));
			usbd_reset_port(up->parent, port, &ps);
		}
	}
	if (err) {
		DPRINTFN(-1,("usb_new_device: set address %d failed\n", addr));
		err = USBD_SET_ADDR_FAILED;
		usbd_remove_device(dev, up);
		return (err);
	}

	/* Allow device time to set new address */
	usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);

	/* Kill the pipe */
	usbd_kill_pipe(dev->default_pipe);
	dev->default_pipe = NULL;

	dev->address = addr;	/* New device address now */
	bus->devices[addr] = dev;

	/* Re-establish the default pipe. */
	err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
			      &dev->default_pipe);
	if (err) {
		usbd_remove_device(dev, up);
		return (err);
	}
	usbd_delay_ms(dev, 200);

	dd = &dev->ddesc;
	/* Get the first 8 bytes of the device descriptor. */
	err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
	if (err) {
		DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
			      "failed\n", addr));
		usbd_remove_device(dev, up);
		return (err);
	}

	if (speed == USB_SPEED_HIGH) {
		/* Max packet size must be 64 (sec 5.5.3). */
		if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
#ifdef DIAGNOSTIC
			kprintf("usbd_new_device: addr=%d bad max packet size\n",
			       addr);
#endif
			dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
		}
	}

	DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
		 "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
		 addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
		 dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
		 dev->speed));

	if (dd->bDescriptorType != UDESC_DEVICE) {
		/* Illegal device descriptor */
		DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",
			     dd->bDescriptorType));
		usbd_remove_device(dev, up);
		return (USBD_INVAL);
	}

	if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
		DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength));
		usbd_remove_device(dev, up);
		return (USBD_INVAL);
	}

	USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);

	err = usbd_reload_device_desc(dev);
	if (err) {
		DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "
			      "failed\n", addr));
		usbd_remove_device(dev, up);
		return (err);
	}

	/* Assume 100mA bus powered for now. Changed when configured. */
	dev->power = USB_MIN_POWER;
	dev->self_powered = 0;

	DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
		 addr, dev, parent));

	err = usbd_probe_and_attach(parent, dev, port, addr);
	if (err) {
		usbd_remove_device(dev, up);
		return (err);
  	}

	usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);

  	return (USBD_NORMAL_COMPLETION);
}
Exemplo n.º 22
0
int
kue_load_fw(struct kue_softc *sc)
{
	usb_device_descriptor_t dd;
	usbd_status		err;
	struct kue_firmware	*fw;
	u_char			*buf;
	size_t			buflen;

	DPRINTFN(1,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));

	/*
	 * First, check if we even need to load the firmware.
	 * If the device was still attached when the system was
	 * rebooted, it may already have firmware loaded in it.
	 * If this is the case, we don't need to do it again.
	 * And in fact, if we try to load it again, we'll hang,
	 * so we have to avoid this condition if we don't want
	 * to look stupid.
	 *
	 * We can test this quickly by checking the bcdRevision
	 * code. The NIC will return a different revision code if
	 * it's probed while the firmware is still loaded and
	 * running.
	 */
	if (usbd_get_device_desc(sc->kue_udev, &dd))
		return (EIO);
	if (UGETW(dd.bcdDevice) >= KUE_WARM_REV) {
		printf("%s: warm boot, no firmware download\n",
		       sc->kue_dev.dv_xname);
		return (0);
	}

	err = loadfirmware("kue", &buf, &buflen);
	if (err) {
		printf("%s: failed loadfirmware of file %s: errno %d\n",
		    sc->kue_dev.dv_xname, "kue", err);
		return (err);
	}
	fw = (struct kue_firmware *)buf;

	printf("%s: cold boot, downloading firmware\n",
	       sc->kue_dev.dv_xname);

	/* Load code segment */
	DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[0], ntohl(fw->codeseglen));
	if (err) {
		printf("%s: failed to load code segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}

	/* Load fixup segment */
	DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[ntohl(fw->codeseglen)], ntohl(fw->fixseglen));
	if (err) {
		printf("%s: failed to load fixup segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}

	/* Send trigger command. */
	DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
		    sc->kue_dev.dv_xname));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)&fw->data[ntohl(fw->codeseglen) + ntohl(fw->fixseglen)],
	    ntohl(fw->trigseglen));
	if (err) {
		printf("%s: failed to load trigger segment: %s\n",
		    sc->kue_dev.dv_xname, usbd_errstr(err));
		free(buf, M_DEVBUF);
		return (EIO);
	}
	free(buf, M_DEVBUF);

	usbd_delay_ms(sc->kue_udev, 10);

	/*
	 * Reload device descriptor.
	 * Why? The chip without the firmware loaded returns
	 * one revision code. The chip with the firmware
	 * loaded and running returns a *different* revision
	 * code. This confuses the quirk mechanism, which is
	 * dependent on the revision data.
	 */
	(void)usbd_reload_device_desc(sc->kue_udev);

	DPRINTFN(1,("%s: %s: done\n", sc->kue_dev.dv_xname, __func__));

	/* Reset the adapter. */
	kue_reset(sc);

	return (0);
}
Exemplo n.º 23
0
int
smsc_chip_init(struct smsc_softc *sc)
{
	int err;
	uint32_t reg_val;
	int burst_cap;

	/* Enter H/W config mode */
	smsc_write_reg(sc, SMSC_HW_CFG, SMSC_HW_CFG_LRST);

	if ((err = smsc_wait_for_bits(sc, SMSC_HW_CFG,
	    SMSC_HW_CFG_LRST)) != 0) {
		smsc_warn_printf(sc, "timed-out waiting for reset to "
		    "complete\n");
		goto init_failed;
	}

	/* Reset the PHY */
	smsc_write_reg(sc, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST);

	if ((err = smsc_wait_for_bits(sc, SMSC_PM_CTRL,
	    SMSC_PM_CTRL_PHY_RST) != 0)) {
		smsc_warn_printf(sc, "timed-out waiting for phy reset to "
		    "complete\n");
		goto init_failed;
	}
	usbd_delay_ms(sc->sc_udev, 40);

	/* Set the mac address */
	if ((err = smsc_setmacaddress(sc, sc->sc_ac.ac_enaddr)) != 0) {
		smsc_warn_printf(sc, "failed to set the MAC address\n");
		goto init_failed;
	}

	/*
	 * Don't know what the HW_CFG_BIR bit is, but following the reset
	 * sequence as used in the Linux driver.
	 */
	if ((err = smsc_read_reg(sc, SMSC_HW_CFG, &reg_val)) != 0) {
		smsc_warn_printf(sc, "failed to read HW_CFG: %d\n", err);
		goto init_failed;
	}
	reg_val |= SMSC_HW_CFG_BIR;
	smsc_write_reg(sc, SMSC_HW_CFG, reg_val);

	/*
	 * There is a so called 'turbo mode' that the linux driver supports, it
	 * seems to allow you to jam multiple frames per Rx transaction.
	 * By default this driver supports that and therefore allows multiple
	 * frames per URB.
	 *
	 * The xfer buffer size needs to reflect this as well, therefore based
	 * on the calculations in the Linux driver the RX bufsize is set to
	 * 18944,
	 *     bufsz = (16 * 1024 + 5 * 512)
	 *
	 * Burst capability is the number of URBs that can be in a burst of
	 * data/ethernet frames.
	 */
#ifdef SMSC_TURBO
	if (sc->sc_udev->speed == USB_SPEED_HIGH)
		burst_cap = 37;
	else
		burst_cap = 128;
#else
	burst_cap = 0;
#endif

	smsc_write_reg(sc, SMSC_BURST_CAP, burst_cap);

	/* Set the default bulk in delay (magic value from Linux driver) */
	smsc_write_reg(sc, SMSC_BULK_IN_DLY, 0x00002000);



	/*
	 * Initialise the RX interface
	 */
	if ((err = smsc_read_reg(sc, SMSC_HW_CFG, &reg_val)) < 0) {
		smsc_warn_printf(sc, "failed to read HW_CFG: (err = %d)\n",
		    err);
		goto init_failed;
	}

	/*
	 * The following setings are used for 'turbo mode', a.k.a multiple
	 * frames per Rx transaction (again info taken form Linux driver).
	 */
#ifdef SMSC_TURBO
	reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE);
#endif

	smsc_write_reg(sc, SMSC_HW_CFG, reg_val);

	/* Clear the status register ? */
	smsc_write_reg(sc, SMSC_INTR_STATUS, 0xffffffff);

	/* Read and display the revision register */
	if ((err = smsc_read_reg(sc, SMSC_ID_REV, &sc->sc_rev_id)) < 0) {
		smsc_warn_printf(sc, "failed to read ID_REV (err = %d)\n", err);
		goto init_failed;
	}

	/* GPIO/LED setup */
	reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | 
	          SMSC_LED_GPIO_CFG_FDX_LED;
	smsc_write_reg(sc, SMSC_LED_GPIO_CFG, reg_val);

	/*
	 * Initialise the TX interface
	 */
	smsc_write_reg(sc, SMSC_FLOW, 0);

	smsc_write_reg(sc, SMSC_AFC_CFG, AFC_CFG_DEFAULT);

	/* Read the current MAC configuration */
	if ((err = smsc_read_reg(sc, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) {
		smsc_warn_printf(sc, "failed to read MAC_CSR (err=%d)\n", err);
		goto init_failed;
	}
	
	/* Vlan */
	smsc_write_reg(sc, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN);

	/*
	 * Start TX
	 */
	sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN;
	smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr);
	smsc_write_reg(sc, SMSC_TX_CFG, SMSC_TX_CFG_ON);

	/*
	 * Start RX
	 */
	sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN;
	smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr);

	return (0);
	
init_failed:
	smsc_err_printf(sc, "smsc_chip_init failed (err=%d)\n", err);
	return (err);
}
Exemplo n.º 24
0
void
ukbd_attach(struct device *parent, struct device *self, void *aux)
{
	struct ukbd_softc *sc = (struct ukbd_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
	usb_hid_descriptor_t *hid;
	u_int32_t qflags;
	const char *parseerr;
	kbd_t layout = (kbd_t)-1;
	struct wskbddev_attach_args a;

	sc->sc_hdev.sc_intr = ukbd_intr;
	sc->sc_hdev.sc_parent = uha->parent;
	sc->sc_hdev.sc_report_id = uha->reportid;

	parseerr = ukbd_parse_desc(sc);
	if (parseerr != NULL) {
		printf("\n%s: attach failed, %s\n",
		       sc->sc_hdev.sc_dev.dv_xname, parseerr);
		return;
	}

	hid = usbd_get_hid_descriptor(uha->uaa->iface);

#ifdef DIAGNOSTIC
	printf(": %d modifier keys, %d key codes",
	    sc->sc_nmod, sc->sc_nkeycode);
#endif

	qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
	sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0;

	/*
	 * Remember if we're the console keyboard.
	 *
	 * XXX This always picks the first keyboard on the
	 * first USB bus, but what else can we really do?
	 */
	if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
		/* Don't let any other keyboard have it. */
		ukbd_is_console = 0;
	}

	if (uha->uaa->vendor == USB_VENDOR_TOPRE &&
	    uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) {
		/* ignore country code on purpose */
	} else {
		if (hid->bCountryCode <= HCC_MAX)
			layout = ukbd_countrylayout[hid->bCountryCode];
#ifdef DIAGNOSTIC
		if (hid->bCountryCode != 0)
			printf(", country code %d", hid->bCountryCode);
#endif
	}
	if (layout == (kbd_t)-1) {
#ifdef UKBD_LAYOUT
		layout = UKBD_LAYOUT;
#else
		layout = KB_US;
#endif
	}
	ukbd_keymapdata.layout = layout;

	printf("\n");

	if (sc->sc_console_keyboard) {
		DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
		wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
		ukbd_enable(sc, 1);
	}

	a.console = sc->sc_console_keyboard;

	a.keymap = &ukbd_keymapdata;

	a.accessops = &ukbd_accessops;
	a.accesscookie = sc;

#ifdef WSDISPLAY_COMPAT_RAWKBD
	timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc);
#endif
	timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc);

	/* Flash the leds; no real purpose, just shows we're alive. */
	ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
	usbd_delay_ms(uha->parent->sc_udev, 400);
	ukbd_set_leds(sc, 0);

	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
}
Exemplo n.º 25
-1
int
ueagle_boot(struct ueagle_softc *sc)
{
	uint16_t zero = 0; /* ;-) */
	usbd_status error;
#define CW(sc, address, offset, data) do {				\
	if ((error = ueagle_cw(sc, address, offset, data)) != 0)	\
		return error;						\
} while (0)

	ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_BOOTIDMA, NULL, 0);
	ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_STARTRESET, NULL, 0);

	usbd_delay_ms(sc->sc_udev, 200);

	ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_ENDRESET, NULL, 0);
	ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPTXMAILBOX, &zero, 2);
	ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPRXMAILBOX, &zero, 2);
	ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_SWAPMAILBOX, &zero, 2);

	usbd_delay_ms(sc->sc_udev, 1000);

	sc->pageno = 0;
	sc->ovl = 0;
	ueagle_loadpage(sc);

	/* wait until modem reaches operational state */
	error = tsleep(UEAGLE_COND_READY(sc), PZERO | PCATCH, "boot", 10 * hz);
	if (error != 0) {
		printf("%s: timeout waiting for operational state\n",
		    sc->sc_dev.dv_xname);
		return error;
	}

	CW(sc, UEAGLE_CMV_CNTL, 0, 1);

	/* send configuration options */
	CW(sc, UEAGLE_CMV_OPTN, 0, UEAGLE_OPTN0);
	CW(sc, UEAGLE_CMV_OPTN, 2, UEAGLE_OPTN2);
	CW(sc, UEAGLE_CMV_OPTN, 7, UEAGLE_OPTN7);

	/* continue with synchronization */
	CW(sc, UEAGLE_CMV_CNTL, 0, 2);

	return kthread_create(ueagle_stat_thread, sc, &sc->stat_thread,
	    sc->sc_dev.dv_xname);
#undef CW
}