예제 #1
0
파일: subr_usbd.c 프로젝트: 2asoft/freebsd
static usb_interface_descriptor_t *
USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf,
    void *start, int32_t intfnum, int32_t altset, int32_t intfclass,
    int32_t intfsubclass, int32_t intfproto)
{
	struct usb_descriptor *next = NULL;
	usb_interface_descriptor_t *desc;

	while ((next = usb_desc_foreach(conf, next)) != NULL) {
		desc = (usb_interface_descriptor_t *)next;
		if (desc->bDescriptorType != UDESC_INTERFACE)
			continue;
		if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
			continue;
		if (!(altset == -1 || desc->bAlternateSetting == altset))
			continue;
		if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
			continue;
		if (!(intfsubclass == -1 ||
		    desc->bInterfaceSubClass == intfsubclass))
			continue;
		if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
			continue;
		return (desc);
	}

	return (NULL);
}
예제 #2
0
/*------------------------------------------------------------------------*
 *	usbd_get_no_alts
 *
 * Return value:
 *   Number of alternate settings for the given interface descriptor
 *   pointer. If the USB descriptor is corrupt, the returned value can
 *   be greater than the actual number of alternate settings.
 *------------------------------------------------------------------------*/
uint8_t
usbd_get_no_alts(struct usb_config_descriptor *cd,
    struct usb_interface_descriptor *id)
{
	struct usb_descriptor *desc;
	uint8_t n;
	uint8_t ifaceno;

	/* Reset interface count */

	n = 0;

	/* Get the interface number */

	ifaceno = id->bInterfaceNumber;

	/* Iterate all the USB descriptors */

	desc = NULL;
	while ((desc = usb_desc_foreach(cd, desc))) {
		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
		    (desc->bLength >= sizeof(*id))) {
			id = (struct usb_interface_descriptor *)desc;
			if (id->bInterfaceNumber == ifaceno) {
				n++;
				if (n == 0xFF)
					break;		/* crazy */
			}
		}
	}
	return (n);
}
예제 #3
0
/*------------------------------------------------------------------------*
 *	usb_idesc_foreach
 *
 * This function will iterate the interface descriptors in the config
 * descriptor. The parse state structure should be zeroed before
 * calling this function the first time.
 *
 * Return values:
 *   NULL: End of descriptors
 *   Else: A valid interface descriptor
 *------------------------------------------------------------------------*/
struct usb_interface_descriptor *
usb_idesc_foreach(struct usb_config_descriptor *cd,
    struct usb_idesc_parse_state *ps)
{
	struct usb_interface_descriptor *id;
	uint8_t new_iface;

	/* retrieve current descriptor */
	id = (struct usb_interface_descriptor *)ps->desc;
	/* default is to start a new interface */
	new_iface = 1;

	while (1) {
		id = (struct usb_interface_descriptor *)
		    usb_desc_foreach(cd, (struct usb_descriptor *)id);
		if (id == NULL)
			break;
		if ((id->bDescriptorType == UDESC_INTERFACE) &&
		    (id->bLength >= sizeof(*id))) {
			if (ps->iface_no_last == id->bInterfaceNumber)
				new_iface = 0;
			ps->iface_no_last = id->bInterfaceNumber;
			break;
		}
	}

	if (ps->desc == NULL) {
		/* first time or zero descriptors */
	} else if (new_iface) {
		/* new interface */
		ps->iface_index ++;
		ps->iface_index_alt = 0;
	} else {
		/* new alternate interface */
		ps->iface_index_alt ++;
	}
#if (USB_IFACE_MAX <= 0)
#error "USB_IFACE_MAX must be defined greater than zero"
#endif
	/* check for too many interfaces */
	if (ps->iface_index >= USB_IFACE_MAX) {
		DPRINTF("Interface limit reached\n");
		id = NULL;
	}

	/* store and return current descriptor */
	ps->desc = (struct usb_descriptor *)id;
	return (id);
}
예제 #4
0
/*------------------------------------------------------------------------*
 *	usbd_get_no_descriptors
 *
 * This function will count the total number of descriptors in the
 * configuration descriptor of type "type".
 *------------------------------------------------------------------------*/
uint8_t
usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type)
{
	struct usb_descriptor *desc = NULL;
	uint8_t count = 0;

	while ((desc = usb_desc_foreach(cd, desc))) {
		if (desc->bDescriptorType == type) {
			count++;
			if (count == 0xFF)
				break;			/* crazy */
		}
	}
	return (count);
}
예제 #5
0
/*------------------------------------------------------------------------*
 *	usb_idesc_foreach
 *
 * This function will iterate the interface descriptors in the config
 * descriptor. The parse state structure should be zeroed before
 * calling this function the first time.
 *
 * Return values:
 *   NULL: End of descriptors
 *   Else: A valid interface descriptor
 *------------------------------------------------------------------------*/
struct usb_interface_descriptor *
usb_idesc_foreach(struct usb_config_descriptor *cd,
    struct usb_idesc_parse_state *ps)
{
	struct usb_interface_descriptor *id;
	uint8_t new_iface;

	/* retrieve current descriptor */
	id = (struct usb_interface_descriptor *)ps->desc;
	/* default is to start a new interface */
	new_iface = 1;

	while (1) {
		id = (struct usb_interface_descriptor *)
		    usb_desc_foreach(cd, (struct usb_descriptor *)id);
		if (id == NULL)
			break;
		if ((id->bDescriptorType == UDESC_INTERFACE) &&
		    (id->bLength >= sizeof(*id))) {
			if (ps->iface_no_last == id->bInterfaceNumber)
				new_iface = 0;
			ps->iface_no_last = id->bInterfaceNumber;
			break;
		}
	}

	if (ps->desc == NULL) {
		/* first time */
	} else if (new_iface) {
		/* new interface */
		ps->iface_index ++;
		ps->iface_index_alt = 0;
	} else {
		/* new alternate interface */
		ps->iface_index_alt ++;
	}

	/* store and return current descriptor */
	ps->desc = (struct usb_descriptor *)id;
	return (id);
}
예제 #6
0
/*------------------------------------------------------------------------*
 *	usb_edesc_foreach
 *
 * This function will iterate all the endpoint descriptors within an
 * interface descriptor. Starting value for the "ped" argument should
 * be a valid interface descriptor.
 *
 * Return values:
 *   NULL: End of descriptors
 *   Else: A valid endpoint descriptor
 *------------------------------------------------------------------------*/
struct usb_endpoint_descriptor *
usb_edesc_foreach(struct usb_config_descriptor *cd,
    struct usb_endpoint_descriptor *ped)
{
	struct usb_descriptor *desc;

	desc = ((struct usb_descriptor *)ped);

	while ((desc = usb_desc_foreach(cd, desc))) {
		if (desc->bDescriptorType == UDESC_INTERFACE) {
			break;
		}
		if (desc->bDescriptorType == UDESC_ENDPOINT) {
			if (desc->bLength < sizeof(*ped)) {
				/* endpoint descriptor is invalid */
				break;
			}
			return ((struct usb_endpoint_descriptor *)desc);
		}
	}
	return (NULL);
}
예제 #7
0
파일: usb_template.c 프로젝트: OpenKod/src
/*------------------------------------------------------------------------*
 *	usb_hw_ep_get_needs
 *
 * This function will figure out the type and number of endpoints
 * which are needed for an USB configuration.
 *
 * Return values:
 *    0: Success.
 * Else: Failure.
 *------------------------------------------------------------------------*/
static uint8_t
usb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues,
    uint8_t ep_type, uint8_t is_complete)
{
	const struct usb_hw_ep_profile *pf;
	struct usb_hw_ep_scratch_sub *ep_iface;
	struct usb_hw_ep_scratch_sub *ep_curr;
	struct usb_hw_ep_scratch_sub *ep_max;
	struct usb_hw_ep_scratch_sub *ep_end;
	struct usb_descriptor *desc;
	struct usb_interface_descriptor *id;
	struct usb_endpoint_descriptor *ed;
	enum usb_dev_speed speed;
	uint16_t wMaxPacketSize;
	uint16_t temp;
	uint8_t ep_no;

	ep_iface = ues->ep_max;
	ep_curr = ues->ep_max;
	ep_end = ues->ep + USB_EP_MAX;
	ep_max = ues->ep_max;
	desc = NULL;
	speed = usbd_get_speed(ues->udev);

repeat:

	while ((desc = usb_desc_foreach(ues->cd, desc))) {

		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
		    (desc->bLength >= sizeof(*id))) {

			id = (void *)desc;

			if (id->bAlternateSetting == 0) {
				/* going forward */
				ep_iface = ep_max;
			} else {
				/* reset */
				ep_curr = ep_iface;
			}
		}
		if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
		    (desc->bLength >= sizeof(*ed))) {

			ed = (void *)desc;

			goto handle_endpoint_desc;
		}
	}
	ues->ep_max = ep_max;
	return (0);

handle_endpoint_desc:
	temp = (ed->bmAttributes & UE_XFERTYPE);

	if (temp == ep_type) {

		if (ep_curr == ep_end) {
			/* too many endpoints */
			return (1);	/* failure */
		}
		wMaxPacketSize = UGETW(ed->wMaxPacketSize);
		if ((wMaxPacketSize & 0xF800) &&
		    (speed == USB_SPEED_HIGH)) {
			/* handle packet multiplier */
			temp = (wMaxPacketSize >> 11) & 3;
			wMaxPacketSize &= 0x7FF;
			if (temp == 1) {
				wMaxPacketSize *= 2;
			} else {
				wMaxPacketSize *= 3;
			}
		}
		/*
		 * Check if we have a fixed endpoint number, else the
		 * endpoint number is allocated dynamically:
		 */
		ep_no = (ed->bEndpointAddress & UE_ADDR);
		if (ep_no != 0) {

			/* get HW endpoint profile */
			(ues->methods->get_hw_ep_profile)
			    (ues->udev, &pf, ep_no);
			if (pf == NULL) {
				/* HW profile does not exist - failure */
				DPRINTFN(0, "Endpoint profile %u "
				    "does not exist\n", ep_no);
				return (1);
			}
			/* reserve fixed endpoint number */
			if (ep_type == UE_CONTROL) {
				ues->bmInAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				ues->bmOutAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if ((pf->max_in_frame_size < wMaxPacketSize) ||
				    (pf->max_out_frame_size < wMaxPacketSize)) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			} else if (ed->bEndpointAddress & UE_DIR_IN) {
				ues->bmInAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if (pf->max_in_frame_size < wMaxPacketSize) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			} else {
				ues->bmOutAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if (pf->max_out_frame_size < wMaxPacketSize) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			}
		} else if (is_complete) {

			/* check if we have enough buffer space */
			if (wMaxPacketSize >
			    ep_curr->max_frame_size) {
				return (1);	/* failure */
			}
			if (ed->bEndpointAddress & UE_DIR_IN) {
				ed->bEndpointAddress =
				    ep_curr->hw_endpoint_in;
			} else {
				ed->bEndpointAddress =
				    ep_curr->hw_endpoint_out;
			}

		} else {

			/* compute the maximum frame size */
			if (ep_curr->max_frame_size < wMaxPacketSize) {
				ep_curr->max_frame_size = wMaxPacketSize;
			}
			if (temp == UE_CONTROL) {
				ep_curr->needs_in = 1;
				ep_curr->needs_out = 1;
			} else {
				if (ed->bEndpointAddress & UE_DIR_IN) {
					ep_curr->needs_in = 1;
				} else {
					ep_curr->needs_out = 1;
				}
			}
			ep_curr->needs_ep_type = ep_type;
		}

		ep_curr++;
		if (ep_max < ep_curr) {
			ep_max = ep_curr;
		}
	}
예제 #8
0
파일: ng_ubt.c 프로젝트: 2asoft/freebsd
static int
ubt_attach(device_t dev)
{
	struct usb_attach_arg		*uaa = device_get_ivars(dev);
	struct ubt_softc		*sc = device_get_softc(dev);
	struct usb_endpoint_descriptor	*ed;
	struct usb_interface_descriptor *id;
	struct usb_interface		*iface;
	uint16_t			wMaxPacketSize;
	uint8_t				alt_index, i, j;
	uint8_t				iface_index[2] = { 0, 1 };

	device_set_usb_desc(dev);

	sc->sc_dev = dev;
	sc->sc_debug = NG_UBT_WARN_LEVEL;

	/* 
	 * Create Netgraph node
	 */

	if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) {
		UBT_ALERT(sc, "could not create Netgraph node\n");
		return (ENXIO);
	}

	/* Name Netgraph node */
	if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) {
		UBT_ALERT(sc, "could not name Netgraph node\n");
		NG_NODE_UNREF(sc->sc_node);
		return (ENXIO);
	}
	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
	NG_NODE_FORCE_WRITER(sc->sc_node);

	/*
	 * Initialize device softc structure
	 */

	/* initialize locks */
	mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF);
	mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE);

	/* initialize packet queues */
	NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);

	/* initialize glue task */
	TASK_INIT(&sc->sc_task, 0, ubt_task, sc);

	/*
	 * Configure Bluetooth USB device. Discover all required USB
	 * interfaces and endpoints.
	 *
	 * USB device must present two interfaces:
	 * 1) Interface 0 that has 3 endpoints
	 *	1) Interrupt endpoint to receive HCI events
	 *	2) Bulk IN endpoint to receive ACL data
	 *	3) Bulk OUT endpoint to send ACL data
	 *
	 * 2) Interface 1 then has 2 endpoints
	 *	1) Isochronous IN endpoint to receive SCO data
 	 *	2) Isochronous OUT endpoint to send SCO data
	 *
	 * Interface 1 (with isochronous endpoints) has several alternate
	 * configurations with different packet size.
	 */

	/*
	 * For interface #1 search alternate settings, and find
	 * the descriptor with the largest wMaxPacketSize
	 */

	wMaxPacketSize = 0;
	alt_index = 0;
	i = 0;
	j = 0;
	ed = NULL;

	/* 
	 * Search through all the descriptors looking for the largest
	 * packet size:
	 */
	while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach(
	    usbd_get_config_descriptor(uaa->device), 
	    (struct usb_descriptor *)ed))) {

		if ((ed->bDescriptorType == UDESC_INTERFACE) &&
		    (ed->bLength >= sizeof(*id))) {
			id = (struct usb_interface_descriptor *)ed;
			i = id->bInterfaceNumber;
			j = id->bAlternateSetting;
		}

		if ((ed->bDescriptorType == UDESC_ENDPOINT) &&
		    (ed->bLength >= sizeof(*ed)) &&
		    (i == 1)) {
			uint16_t temp;

			temp = UGETW(ed->wMaxPacketSize);
			if (temp > wMaxPacketSize) {
				wMaxPacketSize = temp;
				alt_index = j;
			}
		}
	}

	/* Set alt configuration on interface #1 only if we found it */
	if (wMaxPacketSize > 0 &&
	    usbd_set_alt_interface_index(uaa->device, 1, alt_index)) {
		UBT_ALERT(sc, "could not set alternate setting %d " \
			"for interface 1!\n", alt_index);
		goto detach;
	}

	/* Setup transfers for both interfaces */
	if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer,
			ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) {
		UBT_ALERT(sc, "could not allocate transfers\n");
		goto detach;
	}

	/* Claim all interfaces belonging to the Bluetooth part */
	for (i = 1;; i++) {
		iface = usbd_get_iface(uaa->device, i);
		if (iface == NULL)
			break;
		id = usbd_get_interface_descriptor(iface);

		if ((id != NULL) &&
		    (id->bInterfaceClass == UICLASS_WIRELESS) &&
		    (id->bInterfaceSubClass == UISUBCLASS_RF) &&
		    (id->bInterfaceProtocol == UIPROTO_BLUETOOTH)) {
			usbd_set_parent_iface(uaa->device, i,
			    uaa->info.bIfaceIndex);
		}
	}
	return (0); /* success */

detach:
	ubt_detach(dev);

	return (ENXIO);
} /* ubt_attach */