Beispiel #1
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);
}
Beispiel #2
0
void
uticom_attach_hook(void *arg)
{
	struct uticom_softc		*sc = arg;
	usb_config_descriptor_t		*cdesc;
	usb_interface_descriptor_t	*id;
	usb_endpoint_descriptor_t	*ed;
	usbd_status			 err;
	int				 status, i;
	usb_device_descriptor_t		*dd;
	struct ucom_attach_args		 uca;

	/* Initialize endpoints. */
	uca.bulkin = uca.bulkout = -1;
	sc->sc_intr_number = -1;
	sc->sc_intr_pipe = NULL;

	dd = usbd_get_device_descriptor(sc->sc_udev);
	DPRINTF(("%s: uticom_attach: num of configurations %d\n",
	    sc->sc_dev.dv_xname, dd->bNumConfigurations));

	/* The device without firmware has single configuration with single
	 * bulk out interface. */
	if (dd->bNumConfigurations > 1)
		goto fwload_done;

	/* Loading firmware. */
	DPRINTF(("%s: uticom_attach: starting loading firmware\n",
	    sc->sc_dev.dv_xname));

	err = usbd_set_config_index(sc->sc_udev, UTICOM_CONFIG_INDEX, 1);
	if (err) {
		printf("%s: failed to set configuration: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(err));
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Get the config descriptor. */
	cdesc = usbd_get_config_descriptor(sc->sc_udev);

	if (cdesc == NULL) {
		printf("%s: failed to get configuration descriptor\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
	    &sc->sc_iface);
	if (err) {
		printf("%s: failed to get interface: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(err));
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Find the bulk out interface used to upload firmware. */
	id = usbd_get_interface_descriptor(sc->sc_iface);
	sc->sc_iface_number = id->bInterfaceNumber;

	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
			    sc->sc_dev.dv_xname, i);
			usbd_deactivate(sc->sc_udev);
			return;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkout = ed->bEndpointAddress;
			DPRINTF(("%s: uticom_attach: data bulk out num: %d\n",
			    sc->sc_dev.dv_xname, ed->bEndpointAddress));
		}

		if (uca.bulkout == -1) {
			printf("%s: could not find data bulk out\n",
			    sc->sc_dev.dv_xname);
			usbd_deactivate(sc->sc_udev);
			return;
		}
	}

	status = uticom_download_fw(sc, uca.bulkout, sc->sc_udev);

	if (status) {
		printf("%s: firmware download failed\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	} else {
		DPRINTF(("%s: firmware download succeeded\n",
		    sc->sc_dev.dv_xname));
	}

	status = usbd_reload_device_desc(sc->sc_udev);
	if (status) {
		printf("%s: error reloading device descriptor\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

fwload_done:
	dd = usbd_get_device_descriptor(sc->sc_udev);
	DPRINTF(("%s: uticom_attach: num of configurations %d\n",
	    sc->sc_dev.dv_xname, dd->bNumConfigurations));

	err = usbd_set_config_index(sc->sc_udev, UTICOM_ACTIVE_INDEX, 1);
	if (err) {
		printf("%s: failed to set configuration: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(err));
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Get the config descriptor. */
	cdesc = usbd_get_config_descriptor(sc->sc_udev);
	if (cdesc == NULL) {
		printf("%s: failed to get configuration descriptor\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Get the interface (XXX: multiport chips are not supported yet). */
	err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
	    &sc->sc_iface);
	if (err) {
		printf("%s: failed to get interface: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(err));
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Find the interrupt endpoints. */
	id = usbd_get_interface_descriptor(sc->sc_iface);
	sc->sc_iface_number = id->bInterfaceNumber;

	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
			    sc->sc_dev.dv_xname, i);
			usbd_deactivate(sc->sc_udev);
			return;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_intr_number = ed->bEndpointAddress;
			sc->sc_isize = UGETW(ed->wMaxPacketSize);

		}
	}

	if (sc->sc_intr_number == -1) {
		printf("%s: could not find interrupt in\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	/* Keep interface for interrupt. */
	sc->sc_intr_iface = sc->sc_iface;

	/* Find the bulk{in,out} endpoints. */
	id = usbd_get_interface_descriptor(sc->sc_iface);
	sc->sc_iface_number = id->bInterfaceNumber;

	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
			    sc->sc_dev.dv_xname, i);
			usbd_deactivate(sc->sc_udev);
			return;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkin = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkout = ed->bEndpointAddress;
		}
	}

	if (uca.bulkin == -1) {
		printf("%s: could not find data bulk in\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	if (uca.bulkout == -1) {
		printf("%s: could not find data bulk out\n",
		    sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	sc->sc_dtr = sc->sc_rts = -1;

	uca.portno = UCOM_UNK_PORTNO;
	uca.ibufsize = UTICOM_IBUFSZ;
	uca.obufsize = UTICOM_OBUFSZ;
	uca.ibufsizepad = UTICOM_IBUFSZ;
	uca.device = sc->sc_udev;
	uca.iface = sc->sc_iface;
	uca.opkthdrlen = 0;
	uca.methods = &uticom_methods;
	uca.arg = sc;
	uca.info = NULL;

	err = uticom_reset(sc);
	if (err) {
		printf("%s: reset failed: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(err));
		usbd_deactivate(sc->sc_udev);
		return;
	}

	DPRINTF(("%s: uticom_attach: in = 0x%x, out = 0x%x, intr = 0x%x\n",
	    sc->sc_dev.dv_xname, uca.bulkin,
	    uca.bulkout, sc->sc_intr_number));

	sc->sc_subdev = config_found_sm((struct device *)sc, &uca, ucomprint, ucomsubmatch);
}
Beispiel #3
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;
}
Beispiel #4
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);
}
Beispiel #5
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);
}