Example #1
0
/* same as usb_find_desc(), but searches only in the specified interface. */
const usb_cdc_descriptor_t *
usb_find_desc_if(usbd_device_handle dev, int type, int subtype,
		 usb_interface_descriptor_t *id)
{
	usbd_desc_iter_t iter;
	const usb_cdc_descriptor_t *desc;

	if (id == NULL)
		return usb_find_desc(dev, type, subtype);

	usb_desc_iter_init(dev, &iter);

	iter.cur = (void *)id;		/* start from the interface desc */
	usb_desc_iter_next(&iter);	/* and skip it */

	while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
	       != NULL) {
		if (desc->bDescriptorType == UDESC_INTERFACE) {
			/* we ran into the next interface --- not found */
			return NULL;
		}
		if (desc->bDescriptorType == type &&
		    (subtype == USBD_CDCSUBTYPE_ANY ||
		     subtype == desc->bDescriptorSubtype))
			break;
	}
	return desc;
}
Example #2
0
const usb_cdc_descriptor_t *
usb_find_desc(usbd_device_handle dev, int type, int subtype)
{
	usbd_desc_iter_t iter;
	const usb_cdc_descriptor_t *desc;

	usb_desc_iter_init(dev, &iter);
	for (;;) {
		desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
		if (!desc || (desc->bDescriptorType == type &&
			      (subtype == USBD_CDCSUBTYPE_ANY ||
			       subtype == desc->bDescriptorSubtype)))
			break;
	}
	return desc;
}
Example #3
0
void
umodem_attach(struct device *parent, struct device *self, void *aux)
{
	struct umodem_softc *sc = (struct umodem_softc *)self;
	struct usb_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	usb_cdc_cm_descriptor_t *cmd;      
	usb_interface_descriptor_t *idesc;
	const usb_cdc_acm_descriptor_t *acmd;
	const usb_cdc_union_descriptor_t *uniond;
	const usb_descriptor_t *desc;
	usbd_desc_iter_t iter;
	usbd_status err;
	int current_iface_no = -1;
	int i;
	struct ucom_attach_args uca;

	sc->sc_udev = dev;
	sc->sc_ctl_iface = uaa->iface;

	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
	//printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname,
	//    id->bInterfaceClass, id->bInterfaceSubClass);
	sc->sc_ctl_iface_no = id->bInterfaceNumber;

	/* Get the data interface no. and capabilities */
	sc->sc_cm_cap = 0;
	sc->sc_data_iface_no = 0;
	sc->sc_acm_cap = 0;
	usb_desc_iter_init(dev, &iter);
	desc = usb_desc_iter_next(&iter);
	while (desc) {
		if (desc->bDescriptorType == UDESC_INTERFACE) {
		    idesc = (usb_interface_descriptor_t *)desc;
		    current_iface_no = idesc->bInterfaceNumber;
		}
		if (current_iface_no == sc->sc_ctl_iface_no &&
		    desc->bDescriptorType == UDESC_CS_INTERFACE) {
			switch(desc->bDescriptorSubtype) {
			case UDESCSUB_CDC_CM:
				cmd = (usb_cdc_cm_descriptor_t *)desc;
				sc->sc_cm_cap = cmd->bmCapabilities;
				sc->sc_data_iface_no = cmd->bDataInterface;
				break;
			case UDESCSUB_CDC_ACM:
				acmd = (usb_cdc_acm_descriptor_t *)desc;
				sc->sc_acm_cap = acmd->bmCapabilities;
				break;
			case UDESCSUB_CDC_UNION:
				uniond = (usb_cdc_union_descriptor_t *)desc;
				sc->sc_data_iface_no =
				    uniond->bSlaveInterface[0];
				break;
			}
		}
		desc = usb_desc_iter_next(&iter);
	}

	if (sc->sc_data_iface_no == 0) {
		printf("%s: no pointer to data interface\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}

	printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
	       sc->sc_dev.dv_xname, sc->sc_data_iface_no,
	       sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
	       sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");

	/* Get the data interface too. */
	for (i = 0; i < uaa->nifaces; i++) {
		if (uaa->ifaces[i] != NULL) {
			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
			if (id != NULL &&
                            id->bInterfaceNumber == sc->sc_data_iface_no) {
				sc->sc_data_iface = uaa->ifaces[i];
				uaa->ifaces[i] = NULL;
			}
		}
	}
	if (sc->sc_data_iface == NULL) {
		printf("%s: no data interface\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	/*
	 * Find the bulk endpoints.
	 * Iterate over all endpoints in the data interface and take note.
	 */
	uca.bulkin = uca.bulkout = -1;

	id = usbd_get_interface_descriptor(sc->sc_data_iface);
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
				sc->sc_dev.dv_xname, i);
			goto bad;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
                        uca.bulkin = ed->bEndpointAddress;
                } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
                        uca.bulkout = ed->bEndpointAddress;
                }
        }

	if (uca.bulkin == -1) {
		printf("%s: Could not find data bulk in\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}
	if (uca.bulkout == -1) {
		printf("%s: Could not find data bulk out\n",
			sc->sc_dev.dv_xname);
		goto bad;
	}

	if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) {
		sc->sc_cm_over_data = 1;
	} else {
		if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) {
			if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE)
				err = umodem_set_comm_feature(sc,
				    UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED);
			else
				err = 0;
			if (err) {
				printf("%s: could not set data multiplex mode\n",
				       sc->sc_dev.dv_xname);
				goto bad;
			}
			sc->sc_cm_over_data = 1;
		}
	}

	/*
	 * The standard allows for notification messages (to indicate things
	 * like a modem hangup) to come in via an interrupt endpoint
	 * off of the control interface.  Iterate over the endpoints on
	 * the control interface and see if there are any interrupt
	 * endpoints; if there are, then register it.
	 */

	sc->sc_ctl_notify = -1;
	sc->sc_notify_pipe = NULL;

	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
		if (ed == NULL)
			continue;

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
			printf("%s: status change notification available\n",
			       sc->sc_dev.dv_xname);
			sc->sc_ctl_notify = ed->bEndpointAddress;
		}
	}

	sc->sc_dtr = -1;

	uca.portno = UCOM_UNK_PORTNO;
	/* bulkin, bulkout set above */
	uca.ibufsize = UMODEMIBUFSIZE;
	uca.obufsize = UMODEMOBUFSIZE;
	uca.ibufsizepad = UMODEMIBUFSIZE;
	uca.opkthdrlen = 0;
	uca.device = sc->sc_udev;
	uca.iface = sc->sc_data_iface;
	uca.methods = &umodem_methods;
	uca.arg = sc;
	uca.info = NULL;

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   &sc->sc_dev);

	DPRINTF(("umodem_attach: sc=%p\n", sc));
	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);

	return;

 bad:
	sc->sc_dying = 1;
}