Exemplo n.º 1
0
int 
ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
{
	struct usbd_interface *iface;
	usb_endpoint_descriptor_t *ed;
	int err;
	struct ugen_endpoint *sce;
	u_int8_t niface, nendpt, endptno, endpt;
	int dir;

	DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));

	err = usbd_interface_count(sc->sc_udev, &niface);
	if (err)
		return (err);
	if (ifaceidx < 0 || ifaceidx >= niface ||
	    usbd_iface_claimed(sc->sc_udev, ifaceidx))
		return (USBD_INVAL);

	err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
	if (err)
		return (err);
	err = usbd_endpoint_count(iface, &nendpt);
	if (err)
		return (err);
	for (endptno = 0; endptno < nendpt; endptno++) {
		ed = usbd_interface2endpoint_descriptor(iface,endptno);
		endpt = ed->bEndpointAddress;
		dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
		sce->sc = 0;
		sce->edesc = 0;
		sce->iface = 0;
	}

	/* change setting */
	err = usbd_set_interface(iface, altno);
	if (err)
		goto out;

	err = usbd_endpoint_count(iface, &nendpt);
	if (err)
		goto out;

out:
	for (endptno = 0; endptno < nendpt; endptno++) {
		ed = usbd_interface2endpoint_descriptor(iface,endptno);
		endpt = ed->bEndpointAddress;
		dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
		sce->sc = sc;
		sce->edesc = ed;
		sce->iface = iface;
	}
	return (err);
}
Exemplo n.º 2
0
int 
ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
{
	struct usbd_interface *iface;
	usb_config_descriptor_t *cdesc;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	struct ugen_endpoint *sce;
	uint8_t  endptno, endpt;
	int dir, err;

	DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));

	cdesc = usbd_get_config_descriptor(sc->sc_udev);
	if (ifaceidx < 0 || ifaceidx >= cdesc->bNumInterface ||
	    usbd_iface_claimed(sc->sc_udev, ifaceidx))
		return (USBD_INVAL);

	err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
	if (err)
		return (err);
	id = usbd_get_interface_descriptor(iface);
	for (endptno = 0; endptno < id->bNumEndpoints; endptno++) {
		ed = usbd_interface2endpoint_descriptor(iface,endptno);
		endpt = ed->bEndpointAddress;
		dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
		sce->sc = 0;
		sce->edesc = 0;
		sce->iface = 0;
	}

	/* change setting */
	err = usbd_set_interface(iface, altno);
	if (err)
		return (err);

	id = usbd_get_interface_descriptor(iface);
	for (endptno = 0; endptno < id->bNumEndpoints; endptno++) {
		ed = usbd_interface2endpoint_descriptor(iface,endptno);
		endpt = ed->bEndpointAddress;
		dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
		sce->sc = sc;
		sce->edesc = ed;
		sce->iface = iface;
	}
	return (err);
}
Exemplo n.º 3
0
int
_access_endpoint(struct libusb_transfer *transfer)
{
	struct handle_priv *hpriv;
	struct device_priv *dpriv;
	char *s, devnode[16];
	int fd, endpt;
	mode_t mode;

	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;

	endpt = UE_GET_ADDR(transfer->endpoint);
	mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;

	usbi_dbg("endpoint %d mode %d", endpt, mode);

	if (hpriv->endpoints[endpt] < 0) {
		
		strlcpy(devnode, dpriv->devnode, sizeof(devnode));
		s = strchr(devnode, '.');
		snprintf(s, 4, ".%02d", endpt);

		
		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
			if ((fd = open(devnode, mode)) < 0)
				return (-1);

		hpriv->endpoints[endpt] = fd;
	}

	return (hpriv->endpoints[endpt]);
}
Exemplo n.º 4
0
int
_access_endpoint(struct libusb_transfer *transfer)
{
	struct handle_priv *hpriv;
	struct device_priv *dpriv;
	char devnode[16];
	int fd, endpt;
	mode_t mode;

	hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
	dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;

	endpt = UE_GET_ADDR(transfer->endpoint);
	mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;

	usbi_dbg("endpoint %d mode %d", endpt, mode);

	if (hpriv->endpoints[endpt] < 0) {
		/* Pick the right endpoint node */
		snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
		    dpriv->devname, endpt);

		/* We may need to read/write to the same endpoint later. */
		if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
			if ((fd = open(devnode, mode)) < 0)
				return (-1);

		hpriv->endpoints[endpt] = fd;
	}

	return (hpriv->endpoints[endpt]);
}
Exemplo n.º 5
0
static int ensure_ep_open(usb_dev_handle *dev, int ep, int mode)
{
    struct bsd_usb_dev_handle_info *info = dev->impl_info;
    int fd;
    char buf[20];

    /* Get the address for this endpoint; we could check
     * the mode against the direction; but we've done that
     * already in the usb_bulk_read/write.
     */
    ep = UE_GET_ADDR(ep);

    if (info->ep_fd[ep] < 0) {
#ifdef __FreeBSD_kernel__
        snprintf(buf, sizeof(buf) - 1, "%s.%d", dev->device->filename, ep);
#else
        snprintf(buf, sizeof(buf) - 1, "%s.%02d", dev->device->filename, ep);
#endif
        /* Try to open it O_RDWR first for those devices which have in and out
         * endpoints with the same address (eg 0x02 and 0x82)
         */
        fd = open(buf, O_RDWR);
        if (fd < 0 && errno == ENXIO)
            fd = open(buf, mode);
        if (fd < 0)
            USB_ERROR_STR(-errno, "can't open %s for bulk read: %s",
                          buf, strerror(errno));
        info->ep_fd[ep] = fd;
    }

    return info->ep_fd[ep];
}
Exemplo n.º 6
0
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
                       int timeout)
{
    int fd, ret, retrieved = 0, one = 1;

    /* Ensure the endpoint address is correct */
    ep |= USB_ENDPOINT_IN;

    fd = ensure_ep_open(dev, ep, O_RDONLY);
    if (fd < 0) {
        if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
            fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
            fprintf (stderr, "usb_interrupt_read: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
        }
        return fd;
    }

    ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
    if (ret < 0)
        USB_ERROR_STR(-errno, "error setting timeout: %s", strerror(errno));

    ret = ioctl(fd, USB_SET_SHORT_XFER, &one);
    if (ret < 0)
        USB_ERROR_STR(-errno, "error setting short xfer: %s", strerror(errno));

    do {
        ret = read(fd, bytes+retrieved, size-retrieved);
        if (ret < 0)
#ifdef __FreeBSD_kernel__
            USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%d: %s",
                          dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
            USB_ERROR_STR(-errno, "error reading from interrupt endpoint %s.%02d: %s",
                          dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif
        retrieved += ret;
    } while (ret > 0 && retrieved < size);

    return retrieved;
}
Exemplo n.º 7
0
static usb_error_t
usbd_setup_endpoint(irp *ip, uint8_t ifidx,
    struct usb_endpoint_descriptor *ep)
{
	device_t dev = IRP_NDIS_DEV(ip);
	struct ndis_softc *sc = device_get_softc(dev);
	struct ndisusb_ep *ne;
	struct usb_config cfg;
	struct usb_xfer *xfer;
	usb_error_t status;

	/* check for non-supported transfer types */
	if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_CONTROL ||
	    UE_GET_XFERTYPE(ep->bmAttributes) == UE_ISOCHRONOUS) {
		device_printf(dev, "%s: unsuppotted transfer types %#x\n",
		    __func__, UE_GET_XFERTYPE(ep->bmAttributes));
		return (USB_ERR_INVAL);
	}

	ne = &sc->ndisusb_ep[NDISUSB_GET_ENDPT(ep->bEndpointAddress)];
	InitializeListHead(&ne->ne_active);
	InitializeListHead(&ne->ne_pending);
	KeInitializeSpinLock(&ne->ne_lock);
	ne->ne_dirin = UE_GET_DIR(ep->bEndpointAddress) >> 7;

	memset(&cfg, 0, sizeof(struct usb_config));
	cfg.type	= UE_GET_XFERTYPE(ep->bmAttributes);
	cfg.endpoint	= UE_GET_ADDR(ep->bEndpointAddress);
	cfg.direction	= UE_GET_DIR(ep->bEndpointAddress);
	cfg.callback	= &usbd_non_isoc_callback;
	cfg.bufsize	= UGETW(ep->wMaxPacketSize);
	cfg.flags.proxy_buffer = 1;
	if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
		cfg.flags.short_xfer_ok = 1;

	status = usbd_transfer_setup(sc->ndisusb_dev, &ifidx, ne->ne_xfer,
	    &cfg, 1, sc, &sc->ndisusb_mtx);
	if (status != USB_ERR_NORMAL_COMPLETION) {
		device_printf(dev, "couldn't setup xfer: %s\n",
		    usbd_errstr(status));
		return (status);
	}
	xfer = ne->ne_xfer[0];
	usbd_xfer_set_priv(xfer, ne);
	if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
		usbd_xfer_set_timeout(xfer, NDISUSB_NO_TIMEOUT);
	else {
		if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK)
			usbd_xfer_set_timeout(xfer, NDISUSB_TX_TIMEOUT);
		else
			usbd_xfer_set_timeout(xfer, NDISUSB_INTR_TIMEOUT);
	}

	return (status);
}
Exemplo n.º 8
0
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
                        int timeout)
{
    int fd, ret, sent = 0;

    /* Ensure the endpoint address is correct */
    ep &= ~USB_ENDPOINT_IN;

    fd = ensure_ep_open(dev, ep, O_WRONLY);
    if (fd < 0) {
        if (usb_debug >= 2) {
#ifdef __FreeBSD_kernel__
            fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %d\n", UE_GET_ADDR(ep));
#else
            fprintf (stderr, "usb_interrupt_write: got negative open file descriptor for endpoint %02d\n", UE_GET_ADDR(ep));
#endif
        }
        return fd;
    }

    ret = ioctl(fd, USB_SET_TIMEOUT, &timeout);
    if (ret < 0)
        USB_ERROR_STR(-errno, "error setting timeout: %s",
                      strerror(errno));

    do {
        ret = write(fd, bytes+sent, size-sent);
        if (ret < 0)
#ifdef __FreeBSD_kernel__
            USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%d: %s",
                          dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#else
            USB_ERROR_STR(-errno, "error writing to interrupt endpoint %s.%02d: %s",
                          dev->device->filename, UE_GET_ADDR(ep), strerror(errno));
#endif

        sent += ret;
    } while (ret > 0 && sent < size);

    return sent;
}
Exemplo n.º 9
0
static int
init_keyboard(ukbd_state_t *state, int *type, int flags)
{
	usb_endpoint_descriptor_t *ed;
	usbd_status err;

	*type = KB_OTHER;

	state->ks_ifstate |= DISCONNECTED;

	ed = usbd_interface2endpoint_descriptor(state->ks_iface, 0);
	if (!ed) {
		kprintf("ukbd: could not read endpoint descriptor\n");
		return EIO;
	}

	DPRINTFN(10,("ukbd:init_keyboard: \
bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n",
	       ed->bLength, ed->bDescriptorType,
	       UE_GET_ADDR(ed->bEndpointAddress),
	       UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out",
	       UE_GET_XFERTYPE(ed->bmAttributes),
	       UGETW(ed->wMaxPacketSize), ed->bInterval));

	if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
	    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
		kprintf("ukbd: unexpected endpoint\n");
		return EINVAL;
	}

	if ((usbd_get_quirks(state->ks_uaa->device)->uq_flags & UQ_NO_SET_PROTO) == 0) {
		err = usbd_set_protocol(state->ks_iface, 0);
		DPRINTFN(5, ("ukbd:init_keyboard: protocol set\n"));
		if (err) {
			kprintf("ukbd: set protocol failed\n");
			return EIO;
		}
	}
	/* Ignore if SETIDLE fails since it is not crucial. */
	usbd_set_idle(state->ks_iface, 0, 0);

	state->ks_ep_addr = ed->bEndpointAddress;
	state->ks_ifstate &= ~DISCONNECTED;

	return 0;
}
Exemplo n.º 10
0
static usbd_status
alloc_all_endpoints_genuine(struct umidi_softc *sc)
{
	usb_interface_descriptor_t *interface_desc;
	usb_config_descriptor_t *config_desc;
	usb_descriptor_t *desc;
	int num_ep;
	size_t remain, descsize;
	struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
	int epaddr;

	interface_desc = usbd_get_interface_descriptor(sc->sc_iface);
	num_ep = interface_desc->bNumEndpoints;
	sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint) * num_ep,
				      M_USBDEV, M_WAITOK);
	if (!p)
		return USBD_NOMEM;

	sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
	sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0;
	epaddr = -1;

	/* get the list of endpoints for midi stream */
	config_desc = usbd_get_config_descriptor(sc->sc_udev);
	desc = (usb_descriptor_t *) config_desc;
	remain = (size_t)UGETW(config_desc->wTotalLength);
	while (remain>=sizeof(usb_descriptor_t)) {
		descsize = desc->bLength;
		if (descsize>remain || descsize==0)
			break;
		if (desc->bDescriptorType==UDESC_ENDPOINT &&
		    remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
		    UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
			epaddr = TO_EPD(desc)->bEndpointAddress;
		} else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
			   remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
			   epaddr!=-1) {
			if (num_ep>0) {
				num_ep--;
				p->sc = sc;
				p->addr = epaddr;
				p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
				if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
					sc->sc_out_num_endpoints++;
					sc->sc_out_num_jacks += p->num_jacks;
				} else {
					sc->sc_in_num_endpoints++;
					sc->sc_in_num_jacks += p->num_jacks;
				}
				p++;
			}
		} else
			epaddr = -1;
		desc = NEXT_D(desc);
		remain-=descsize;
	}

	/* sort endpoints */
	num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints;
	p = sc->sc_endpoints;
	endep = p + num_ep;
	while (p<endep) {
		lowest = p;
		for (q=p+1; q<endep; q++) {
			if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN &&
			     UE_GET_DIR(q->addr)==UE_DIR_OUT) ||
			    ((UE_GET_DIR(lowest->addr)==
			      UE_GET_DIR(q->addr)) &&
			     (UE_GET_ADDR(lowest->addr)>
			      UE_GET_ADDR(q->addr))))
				lowest = q;
		}
		if (lowest != p) {
			memcpy((void *)&tmpep, (void *)p, sizeof(tmpep));
			memcpy((void *)p, (void *)lowest, sizeof(tmpep));
			memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep));
		}
		p->num_open = 0;
		p++;
	}

	sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
	sc->sc_in_ep =
	    sc->sc_in_num_endpoints ?
		sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;

	return USBD_NORMAL_COMPLETION;
}
Exemplo n.º 11
0
int
ugen_set_config(struct ugen_softc *sc, int configno)
{
	struct usbd_device *dev = sc->sc_udev;
	usb_config_descriptor_t *cdesc;
	struct usbd_interface *iface;
	usb_endpoint_descriptor_t *ed;
	struct ugen_endpoint *sce;
	u_int8_t niface, nendpt;
	int ifaceno, endptno, endpt;
	int err;
	int dir;

	DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
		    sc->sc_dev.dv_xname, configno, sc));

	/*
	 * We start at 1, not 0, because we don't care whether the
	 * control endpoint is open or not. It is always present.
	 */
	for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++)
		if (sc->sc_is_open[endptno]) {
			DPRINTFN(1,
			     ("ugen_set_config: %s - endpoint %d is open\n",
			      sc->sc_dev.dv_xname, endptno));
			return (USBD_IN_USE);
		}

	/* Avoid setting the current value. */
	cdesc = usbd_get_config_descriptor(dev);
	if (!cdesc || cdesc->bConfigurationValue != configno) {
		if (sc->sc_secondary) {
			printf("%s: secondary, not changing config to %d\n",
			    __func__, configno);
			return (USBD_IN_USE);
		} else {
			err = usbd_set_config_no(dev, configno, 1);
			if (err)
				return (err);
		}
	}

	err = usbd_interface_count(dev, &niface);
	if (err)
		return (err);
	memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
	for (ifaceno = 0; ifaceno < niface; ifaceno++) {
		DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
		if (usbd_iface_claimed(sc->sc_udev, ifaceno)) {
			DPRINTF(("%s: iface %d not available\n", __func__,
			    ifaceno));
			continue;
		}
		err = usbd_device2interface_handle(dev, ifaceno, &iface);
		if (err)
			return (err);
		err = usbd_endpoint_count(iface, &nendpt);
		if (err)
			return (err);
		for (endptno = 0; endptno < nendpt; endptno++) {
			ed = usbd_interface2endpoint_descriptor(iface,endptno);
			endpt = ed->bEndpointAddress;
			dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
			sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
			DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
				    "(%d,%d), sce=%p\n",
				    endptno, endpt, UE_GET_ADDR(endpt),
				    UE_GET_DIR(endpt), sce));
			sce->sc = sc;
			sce->edesc = ed;
			sce->iface = iface;
		}
	}
	return (0);
}
Exemplo n.º 12
0
void
uvisor_attach(struct device *parent, struct device *self, void *aux)
{
	struct uvisor_softc *sc = (struct uvisor_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct usbd_device *dev = uaa->device;
	struct usbd_interface *iface;
	usb_interface_descriptor_t *id;
	struct uvisor_connection_info coninfo;
	struct uvisor_palm_connection_info palmconinfo;
	usb_endpoint_descriptor_t *ed;
	int i, j, hasin, hasout, port;
	usbd_status err;
	struct ucom_attach_args uca;

	DPRINTFN(10,("\nuvisor_attach: sc=%p\n", sc));

	/* Move the device into the configured state. */
	err = usbd_set_config_index(dev, UVISOR_CONFIG_INDEX, 1);
	if (err) {
		printf(": failed to set configuration, err=%s\n",
		    usbd_errstr(err));
		goto bad;
	}

	err = usbd_device2interface_handle(dev, UVISOR_IFACE_INDEX, &iface);
	if (err) {
		printf(": failed to get interface, err=%s\n",
		    usbd_errstr(err));
		goto bad;
	}

	sc->sc_flags = uvisor_lookup(uaa->vendor, uaa->product)->uv_flags;
	sc->sc_vendor = uaa->vendor;
	
	if ((sc->sc_flags & (VISOR | PALM4)) == 0) {
		printf("%s: device is neither visor nor palm\n", 
		    sc->sc_dev.dv_xname);
		goto bad;
	}

	id = usbd_get_interface_descriptor(iface);

	sc->sc_udev = dev;
	sc->sc_iface = iface;

	uca.ibufsize = UVISORIBUFSIZE;
	uca.obufsize = UVISOROBUFSIZE;
	uca.ibufsizepad = UVISORIBUFSIZE;
	uca.opkthdrlen = 0;
	uca.device = dev;
	uca.iface = iface;
	uca.methods = &uvisor_methods;
	uca.arg = sc;

	err = uvisor_init(sc, &coninfo, &palmconinfo);
	if (err) {
		printf("%s: init failed, %s\n", sc->sc_dev.dv_xname,
		       usbd_errstr(err));
		goto bad;
	}

	if (sc->sc_flags & VISOR) {
		sc->sc_numcon = UGETW(coninfo.num_ports);
		if (sc->sc_numcon > UVISOR_MAX_CONN)
			sc->sc_numcon = UVISOR_MAX_CONN;

		/* Attach a ucom for each connection. */
		for (i = 0; i < sc->sc_numcon; ++i) {
			switch (coninfo.connections[i].port_function_id) {
			case UVISOR_FUNCTION_GENERIC:
				uca.info = "Generic";
				break;
			case UVISOR_FUNCTION_DEBUGGER:
				uca.info = "Debugger";
				break;
			case UVISOR_FUNCTION_HOTSYNC:
				uca.info = "HotSync";
				break;
			case UVISOR_FUNCTION_REMOTE_FILE_SYS:
				uca.info = "Remote File System";
				break;
			default:
				uca.info = "unknown";
				break;
			}
			port = coninfo.connections[i].port;
			uca.portno = port;
			uca.bulkin = port | UE_DIR_IN;
			uca.bulkout = port | UE_DIR_OUT;
			/* Verify that endpoints exist. */
			hasin = 0;
			hasout = 0;
			for (j = 0; j < id->bNumEndpoints; j++) {
				ed = usbd_interface2endpoint_descriptor(iface, j);
				if (ed == NULL)
					break;
				if (UE_GET_ADDR(ed->bEndpointAddress) == port &&
				    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
					if (UE_GET_DIR(ed->bEndpointAddress)
					    == UE_DIR_IN)
						hasin++;
					else
						hasout++;
				}
			}
			if (hasin == 1 && hasout == 1)
				sc->sc_subdevs[i] = config_found_sm(self, &uca,
				    ucomprint, ucomsubmatch);
			else
				printf("%s: no proper endpoints for port %d (%d,%d)\n",
				    sc->sc_dev.dv_xname, port, hasin, hasout);
		}
	} else {
		sc->sc_numcon = palmconinfo.num_ports;
		if (sc->sc_numcon > UVISOR_MAX_CONN)
			sc->sc_numcon = UVISOR_MAX_CONN;

		/* Attach a ucom for each connection. */
		for (i = 0; i < sc->sc_numcon; ++i) {
			/*
			 * XXX this should copy out 4-char string from the
			 * XXX port_function_id, but where would the string go?
			 * XXX uca.info is a const char *, not an array.
			 */
			uca.info = "sync";
			uca.portno = i;
			if (palmconinfo.endpoint_numbers_different) {
				port = palmconinfo.connections[i].end_point_info;
				uca.bulkin = (port >> 4) | UE_DIR_IN;
				uca.bulkout = (port & 0xf) | UE_DIR_OUT;
			} else {
				port = palmconinfo.connections[i].port;
				uca.bulkin = port | UE_DIR_IN;
				uca.bulkout = port | UE_DIR_OUT;
			}
			sc->sc_subdevs[i] = config_found_sm(self, &uca,
			    ucomprint, ucomsubmatch);
		}