MFp4 //depot/projects/usb@159866
- memory usage reduction by only allocating the required USB pipes and USB interfaces. - cleanup some USB parsing functions to be more flexible. Submitted by: Hans Petter Selasky
This commit is contained in:
parent
0ed53d4515
commit
bdd4120608
@ -254,8 +254,8 @@ usb2_bus_detach(struct usb2_proc_msg *pm)
|
||||
* Free USB Root device, but not any sub-devices, hence they
|
||||
* are freed by the caller of this function:
|
||||
*/
|
||||
usb2_detach_device(udev, USB_IFACE_INDEX_ANY, 0);
|
||||
usb2_free_device(udev);
|
||||
usb2_free_device(udev,
|
||||
USB_UNCFG_FLAG_FREE_EP0);
|
||||
|
||||
mtx_unlock(&Giant);
|
||||
USB_BUS_LOCK(bus);
|
||||
|
@ -57,10 +57,10 @@
|
||||
|
||||
/* function prototypes */
|
||||
|
||||
static void usb2_fill_pipe_data(struct usb2_device *, uint8_t,
|
||||
static void usb2_init_pipe(struct usb2_device *, uint8_t,
|
||||
struct usb2_endpoint_descriptor *, struct usb2_pipe *);
|
||||
static void usb2_free_pipe_data(struct usb2_device *, uint8_t, uint8_t);
|
||||
static void usb2_free_iface_data(struct usb2_device *);
|
||||
static void usb2_unconfigure(struct usb2_device *, uint8_t);
|
||||
static void usb2_detach_device(struct usb2_device *, uint8_t, uint8_t);
|
||||
static void usb2_detach_device_sub(struct usb2_device *, device_t *,
|
||||
uint8_t);
|
||||
static uint8_t usb2_probe_and_attach_sub(struct usb2_device *,
|
||||
@ -70,11 +70,10 @@ static void usb2_init_attach_arg(struct usb2_device *,
|
||||
static void usb2_suspend_resume_sub(struct usb2_device *, device_t,
|
||||
uint8_t);
|
||||
static void usb2_clear_stall_proc(struct usb2_proc_msg *_pm);
|
||||
usb2_error_t usb2_config_parse(struct usb2_device *, uint8_t, uint8_t);
|
||||
#if USB_HAVE_STRINGS
|
||||
static void usb2_check_strings(struct usb2_device *);
|
||||
#endif
|
||||
static usb2_error_t usb2_fill_iface_data(struct usb2_device *, uint8_t,
|
||||
uint8_t);
|
||||
#if USB_HAVE_UGEN
|
||||
static void usb2_notify_addq(const char *type, struct usb2_device *);
|
||||
static void usb2_fifo_free_wrap(struct usb2_device *, uint8_t, uint8_t);
|
||||
@ -268,30 +267,32 @@ usb2_interface_count(struct usb2_device *udev, uint8_t *count)
|
||||
*count = 0;
|
||||
return (USB_ERR_NOT_CONFIGURED);
|
||||
}
|
||||
*count = udev->cdesc->bNumInterface;
|
||||
*count = udev->ifaces_max;
|
||||
return (USB_ERR_NORMAL_COMPLETION);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_fill_pipe_data
|
||||
* usb2_init_pipe
|
||||
*
|
||||
* This function will initialise the USB pipe structure pointed to by
|
||||
* the "pipe" argument.
|
||||
* the "pipe" argument. The structure pointed to by "pipe" must be
|
||||
* zeroed before calling this function.
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb2_fill_pipe_data(struct usb2_device *udev, uint8_t iface_index,
|
||||
usb2_init_pipe(struct usb2_device *udev, uint8_t iface_index,
|
||||
struct usb2_endpoint_descriptor *edesc, struct usb2_pipe *pipe)
|
||||
{
|
||||
struct usb2_bus_methods *methods;
|
||||
|
||||
bzero(pipe, sizeof(*pipe));
|
||||
methods = udev->bus->methods;
|
||||
|
||||
(udev->bus->methods->pipe_init) (udev, edesc, pipe);
|
||||
(methods->pipe_init) (udev, edesc, pipe);
|
||||
|
||||
if (pipe->methods == NULL) {
|
||||
/* the pipe is invalid: just return */
|
||||
/* check for invalid pipe */
|
||||
if (pipe->methods == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialise USB pipe structure */
|
||||
pipe->edesc = edesc;
|
||||
pipe->iface_index = iface_index;
|
||||
@ -299,40 +300,14 @@ usb2_fill_pipe_data(struct usb2_device *udev, uint8_t iface_index,
|
||||
pipe->pipe_q.command = &usb2_pipe_start;
|
||||
|
||||
/* clear stall, if any */
|
||||
if (udev->bus->methods->clear_stall) {
|
||||
if (methods->clear_stall != NULL) {
|
||||
USB_BUS_LOCK(udev->bus);
|
||||
(udev->bus->methods->clear_stall) (udev, pipe);
|
||||
(methods->clear_stall) (udev, pipe);
|
||||
USB_BUS_UNLOCK(udev->bus);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_free_pipe_data
|
||||
*
|
||||
* This function will free USB pipe data for the given interface
|
||||
* index. Hence we do not have any dynamic allocations we simply clear
|
||||
* "pipe->edesc" to indicate that the USB pipe structure can be
|
||||
* reused. The pipes belonging to the given interface should not be in
|
||||
* use when this function is called and no check is performed to
|
||||
* prevent this.
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb2_free_pipe_data(struct usb2_device *udev,
|
||||
uint8_t iface_index, uint8_t iface_mask)
|
||||
{
|
||||
struct usb2_pipe *pipe = udev->pipes;
|
||||
struct usb2_pipe *pipe_end = udev->pipes + USB_EP_MAX;
|
||||
|
||||
while (pipe != pipe_end) {
|
||||
if ((pipe->iface_index & iface_mask) == iface_index) {
|
||||
/* free pipe */
|
||||
pipe->edesc = NULL;
|
||||
}
|
||||
pipe++;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
/*-----------------------------------------------------------------------*
|
||||
* usb2_pipe_foreach
|
||||
*
|
||||
* This function will iterate all the USB endpoints except the control
|
||||
@ -367,123 +342,38 @@ usb2_pipe_foreach(struct usb2_device *udev, struct usb2_pipe *pipe)
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_fill_iface_data
|
||||
*
|
||||
* This function will fill in interface data and allocate USB pipes
|
||||
* for all the endpoints that belong to the given interface. This
|
||||
* function is typically called when setting the configuration or when
|
||||
* setting an alternate interface.
|
||||
*------------------------------------------------------------------------*/
|
||||
static usb2_error_t
|
||||
usb2_fill_iface_data(struct usb2_device *udev,
|
||||
uint8_t iface_index, uint8_t alt_index)
|
||||
{
|
||||
struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
|
||||
struct usb2_pipe *pipe;
|
||||
struct usb2_pipe *pipe_end;
|
||||
struct usb2_interface_descriptor *id;
|
||||
struct usb2_endpoint_descriptor *ed = NULL;
|
||||
struct usb2_descriptor *desc;
|
||||
uint8_t nendpt;
|
||||
|
||||
if (iface == NULL) {
|
||||
return (USB_ERR_INVAL);
|
||||
}
|
||||
DPRINTFN(5, "iface_index=%d alt_index=%d\n",
|
||||
iface_index, alt_index);
|
||||
|
||||
sx_assert(udev->default_sx + 1, SA_LOCKED);
|
||||
|
||||
pipe = udev->pipes;
|
||||
pipe_end = udev->pipes + USB_EP_MAX;
|
||||
|
||||
/*
|
||||
* Check if any USB pipes on the given USB interface are in
|
||||
* use:
|
||||
*/
|
||||
while (pipe != pipe_end) {
|
||||
if ((pipe->edesc != NULL) &&
|
||||
(pipe->iface_index == iface_index) &&
|
||||
(pipe->refcount != 0)) {
|
||||
return (USB_ERR_IN_USE);
|
||||
}
|
||||
pipe++;
|
||||
}
|
||||
|
||||
pipe = &udev->pipes[0];
|
||||
|
||||
id = usb2_find_idesc(udev->cdesc, iface_index, alt_index);
|
||||
if (id == NULL) {
|
||||
return (USB_ERR_INVAL);
|
||||
}
|
||||
/*
|
||||
* Free old pipes after we know that an interface descriptor exists,
|
||||
* if any.
|
||||
*/
|
||||
usb2_free_pipe_data(udev, iface_index, 0 - 1);
|
||||
|
||||
/* Setup USB interface structure */
|
||||
iface->idesc = id;
|
||||
iface->alt_index = alt_index;
|
||||
iface->parent_iface_index = USB_IFACE_INDEX_ANY;
|
||||
|
||||
nendpt = id->bNumEndpoints;
|
||||
DPRINTFN(5, "found idesc nendpt=%d\n", nendpt);
|
||||
|
||||
desc = (void *)id;
|
||||
|
||||
while (nendpt--) {
|
||||
DPRINTFN(11, "endpt=%d\n", nendpt);
|
||||
|
||||
while ((desc = usb2_desc_foreach(udev->cdesc, desc))) {
|
||||
if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
|
||||
(desc->bLength >= sizeof(*ed))) {
|
||||
goto found;
|
||||
}
|
||||
if (desc->bDescriptorType == UDESC_INTERFACE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto error;
|
||||
|
||||
found:
|
||||
ed = (void *)desc;
|
||||
|
||||
/* find a free pipe */
|
||||
while (pipe != pipe_end) {
|
||||
if (pipe->edesc == NULL) {
|
||||
/* pipe is free */
|
||||
usb2_fill_pipe_data(udev, iface_index, ed, pipe);
|
||||
break;
|
||||
}
|
||||
pipe++;
|
||||
}
|
||||
}
|
||||
return (USB_ERR_NORMAL_COMPLETION);
|
||||
|
||||
error:
|
||||
/* passed end, or bad desc */
|
||||
DPRINTFN(0, "%s: bad descriptor(s), addr=%d!\n",
|
||||
__FUNCTION__, udev->address);
|
||||
|
||||
/* free old pipes if any */
|
||||
usb2_free_pipe_data(udev, iface_index, 0 - 1);
|
||||
return (USB_ERR_INVAL);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_free_iface_data
|
||||
* usb2_unconfigure
|
||||
*
|
||||
* This function will free all USB interfaces and USB pipes belonging
|
||||
* to an USB device.
|
||||
*
|
||||
* Flag values, see "USB_UNCFG_FLAG_XXX".
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb2_free_iface_data(struct usb2_device *udev)
|
||||
usb2_unconfigure(struct usb2_device *udev, uint8_t flag)
|
||||
{
|
||||
struct usb2_interface *iface = udev->ifaces;
|
||||
struct usb2_interface *iface_end = udev->ifaces + USB_IFACE_MAX;
|
||||
uint8_t do_unlock;
|
||||
|
||||
/* mtx_assert() */
|
||||
/* automatic locking */
|
||||
if (sx_xlocked(udev->default_sx + 1)) {
|
||||
do_unlock = 0;
|
||||
} else {
|
||||
do_unlock = 1;
|
||||
sx_xlock(udev->default_sx + 1);
|
||||
}
|
||||
|
||||
/* detach all interface drivers */
|
||||
usb2_detach_device(udev, USB_IFACE_INDEX_ANY, flag);
|
||||
|
||||
#if USB_HAVE_UGEN
|
||||
/* free all FIFOs except control endpoint FIFOs */
|
||||
usb2_fifo_free_wrap(udev, USB_IFACE_INDEX_ANY, flag);
|
||||
|
||||
/*
|
||||
* Free all cdev's, if any.
|
||||
*/
|
||||
usb2_cdev_free(udev);
|
||||
#endif
|
||||
|
||||
#if USB_HAVE_COMPAT_LINUX
|
||||
/* free Linux compat device, if any */
|
||||
@ -492,18 +382,10 @@ usb2_free_iface_data(struct usb2_device *udev)
|
||||
udev->linux_dev = NULL;
|
||||
}
|
||||
#endif
|
||||
/* free all pipes, if any */
|
||||
usb2_free_pipe_data(udev, 0, 0);
|
||||
|
||||
/* free all interfaces, if any */
|
||||
while (iface != iface_end) {
|
||||
iface->idesc = NULL;
|
||||
iface->alt_index = 0;
|
||||
iface->parent_iface_index = USB_IFACE_INDEX_ANY;
|
||||
iface++;
|
||||
}
|
||||
usb2_config_parse(udev, USB_IFACE_INDEX_ANY, USB_CFG_FREE);
|
||||
|
||||
/* free "cdesc" after "ifaces", if any */
|
||||
/* free "cdesc" after "ifaces" and "pipes", if any */
|
||||
if (udev->cdesc != NULL) {
|
||||
if (udev->flags.usb2_mode != USB_MODE_DEVICE)
|
||||
free(udev->cdesc, M_USB);
|
||||
@ -512,6 +394,10 @@ usb2_free_iface_data(struct usb2_device *udev)
|
||||
/* set unconfigured state */
|
||||
udev->curr_config_no = USB_UNCONFIG_NO;
|
||||
udev->curr_config_index = USB_UNCONFIG_INDEX;
|
||||
|
||||
if (do_unlock) {
|
||||
sx_unlock(udev->default_sx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
@ -533,7 +419,6 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
struct usb2_config_descriptor *cdp;
|
||||
uint16_t power;
|
||||
uint16_t max_power;
|
||||
uint8_t nifc;
|
||||
uint8_t selfpowered;
|
||||
uint8_t do_unlock;
|
||||
usb2_error_t err;
|
||||
@ -548,22 +433,12 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
sx_xlock(udev->default_sx + 1);
|
||||
}
|
||||
|
||||
/* detach all interface drivers */
|
||||
usb2_detach_device(udev, USB_IFACE_INDEX_ANY, 1);
|
||||
|
||||
#if USB_HAVE_UGEN
|
||||
/* free all FIFOs except control endpoint FIFOs */
|
||||
usb2_fifo_free_wrap(udev, USB_IFACE_INDEX_ANY, 0);
|
||||
|
||||
/* free all configuration data structures */
|
||||
usb2_cdev_free(udev);
|
||||
#endif
|
||||
usb2_free_iface_data(udev);
|
||||
usb2_unconfigure(udev, USB_UNCFG_FLAG_FREE_SUBDEV);
|
||||
|
||||
if (index == USB_UNCONFIG_INDEX) {
|
||||
/*
|
||||
* Leave unallocated when unconfiguring the
|
||||
* device. "usb2_free_iface_data()" will also reset
|
||||
* device. "usb2_unconfigure()" will also reset
|
||||
* the current config number and index.
|
||||
*/
|
||||
err = usb2_req_set_config(udev, NULL, USB_UNCONFIG_NO);
|
||||
@ -585,10 +460,6 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
|
||||
udev->cdesc = cdp;
|
||||
|
||||
if (cdp->bNumInterface > USB_IFACE_MAX) {
|
||||
DPRINTFN(0, "too many interfaces: %d\n", cdp->bNumInterface);
|
||||
cdp->bNumInterface = USB_IFACE_MAX;
|
||||
}
|
||||
/* Figure out if the device is self or bus powered. */
|
||||
selfpowered = 0;
|
||||
if ((!udev->flags.uq_bus_powered) &&
|
||||
@ -665,14 +536,17 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
/* Allocate and fill interface data. */
|
||||
nifc = cdp->bNumInterface;
|
||||
while (nifc--) {
|
||||
err = usb2_fill_iface_data(udev, nifc, 0);
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = usb2_config_parse(udev, USB_IFACE_INDEX_ANY, USB_CFG_ALLOC);
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = usb2_config_parse(udev, USB_IFACE_INDEX_ANY, USB_CFG_INIT);
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#if USB_HAVE_UGEN
|
||||
/* create device nodes for each endpoint */
|
||||
usb2_cdev_create(udev);
|
||||
@ -681,10 +555,7 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
done:
|
||||
DPRINTF("error=%s\n", usb2_errstr(err));
|
||||
if (err) {
|
||||
#if USB_HAVE_UGEN
|
||||
usb2_cdev_free(udev);
|
||||
#endif
|
||||
usb2_free_iface_data(udev);
|
||||
usb2_unconfigure(udev, USB_UNCFG_FLAG_FREE_SUBDEV);
|
||||
}
|
||||
if (do_unlock) {
|
||||
sx_unlock(udev->default_sx + 1);
|
||||
@ -692,6 +563,205 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_config_parse
|
||||
*
|
||||
* This function will allocate and free USB interfaces and USB pipes,
|
||||
* parse the USB configuration structure and initialise the USB pipes
|
||||
* and interfaces. If "iface_index" is not equal to
|
||||
* "USB_IFACE_INDEX_ANY" then the "cmd" parameter is the
|
||||
* alternate_setting to be selected for the given interface. Else the
|
||||
* "cmd" parameter is defined by "USB_CFG_XXX". "iface_index" can be
|
||||
* "USB_IFACE_INDEX_ANY" or a valid USB interface index. This function
|
||||
* is typically called when setting the configuration or when setting
|
||||
* an alternate interface.
|
||||
*
|
||||
* Returns:
|
||||
* 0: Success
|
||||
* Else: Failure
|
||||
*------------------------------------------------------------------------*/
|
||||
usb2_error_t
|
||||
usb2_config_parse(struct usb2_device *udev, uint8_t iface_index, uint8_t cmd)
|
||||
{
|
||||
struct usb2_idesc_parse_state ips;
|
||||
struct usb2_interface_descriptor *id;
|
||||
struct usb2_endpoint_descriptor *ed;
|
||||
struct usb2_interface *iface;
|
||||
struct usb2_pipe *pipe;
|
||||
usb2_error_t err;
|
||||
uint8_t ep_curr;
|
||||
uint8_t ep_max;
|
||||
uint8_t temp;
|
||||
uint8_t do_init;
|
||||
uint8_t alt_index;
|
||||
|
||||
if (iface_index != USB_IFACE_INDEX_ANY) {
|
||||
/* parameter overload */
|
||||
alt_index = cmd;
|
||||
cmd = USB_CFG_INIT;
|
||||
} else {
|
||||
/* not used */
|
||||
alt_index = 0;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
DPRINTFN(5, "iface_index=%d cmd=%d\n",
|
||||
iface_index, cmd);
|
||||
|
||||
if (cmd == USB_CFG_FREE)
|
||||
goto cleanup;
|
||||
|
||||
if (cmd == USB_CFG_INIT) {
|
||||
sx_assert(udev->default_sx + 1, SA_LOCKED);
|
||||
|
||||
/* check for in-use pipes */
|
||||
|
||||
pipe = udev->pipes;
|
||||
ep_max = udev->pipes_max;
|
||||
while (ep_max--) {
|
||||
/* look for matching pipes */
|
||||
if ((iface_index == USB_IFACE_INDEX_ANY) ||
|
||||
(iface_index == pipe->iface_index)) {
|
||||
if (pipe->refcount != 0) {
|
||||
/*
|
||||
* This typically indicates a
|
||||
* more serious error.
|
||||
*/
|
||||
err = USB_ERR_IN_USE;
|
||||
} else {
|
||||
/* reset pipe */
|
||||
memset(pipe, 0, sizeof(*pipe));
|
||||
/* make sure we don't zero the pipe again */
|
||||
pipe->iface_index = USB_IFACE_INDEX_ANY;
|
||||
}
|
||||
}
|
||||
pipe++;
|
||||
}
|
||||
|
||||
if (err)
|
||||
return (err);
|
||||
}
|
||||
|
||||
memset(&ips, 0, sizeof(ips));
|
||||
|
||||
ep_curr = 0;
|
||||
ep_max = 0;
|
||||
|
||||
while ((id = usb2_idesc_foreach(udev->cdesc, &ips))) {
|
||||
|
||||
/* check for interface overflow */
|
||||
if (ips.iface_index == USB_IFACE_MAX)
|
||||
break; /* crazy */
|
||||
|
||||
iface = udev->ifaces + ips.iface_index;
|
||||
|
||||
/* check for specific interface match */
|
||||
|
||||
if (cmd == USB_CFG_INIT) {
|
||||
if ((iface_index != USB_IFACE_INDEX_ANY) &&
|
||||
(iface_index != ips.iface_index)) {
|
||||
/* wrong interface */
|
||||
do_init = 0;
|
||||
} else if (alt_index != ips.iface_index_alt) {
|
||||
/* wrong alternate setting */
|
||||
do_init = 0;
|
||||
} else {
|
||||
/* initialise interface */
|
||||
do_init = 1;
|
||||
}
|
||||
} else
|
||||
do_init = 0;
|
||||
|
||||
/* check for new interface */
|
||||
if (ips.iface_index_alt == 0) {
|
||||
/* update current number of endpoints */
|
||||
ep_curr = ep_max;
|
||||
}
|
||||
/* check for init */
|
||||
if (do_init) {
|
||||
/* setup the USB interface structure */
|
||||
iface->idesc = id;
|
||||
/* default setting */
|
||||
iface->parent_iface_index = USB_IFACE_INDEX_ANY;
|
||||
/* set alternate index */
|
||||
iface->alt_index = alt_index;
|
||||
}
|
||||
|
||||
DPRINTFN(5, "found idesc nendpt=%d\n", id->bNumEndpoints);
|
||||
|
||||
ed = (struct usb2_endpoint_descriptor *)id;
|
||||
|
||||
temp = ep_curr;
|
||||
|
||||
/* iterate all the endpoint descriptors */
|
||||
while ((ed = usb2_edesc_foreach(udev->cdesc, ed))) {
|
||||
|
||||
if (temp == USB_EP_MAX)
|
||||
break; /* crazy */
|
||||
|
||||
pipe = udev->pipes + temp;
|
||||
|
||||
if (do_init) {
|
||||
usb2_init_pipe(udev,
|
||||
ips.iface_index, ed, pipe);
|
||||
}
|
||||
|
||||
temp ++;
|
||||
|
||||
/* find maximum number of endpoints */
|
||||
if (ep_max < temp)
|
||||
ep_max = temp;
|
||||
|
||||
/* optimalisation */
|
||||
id = (struct usb2_interface_descriptor *)ed;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: It is valid to have no interfaces and no endpoints! */
|
||||
|
||||
if (cmd == USB_CFG_ALLOC) {
|
||||
udev->ifaces_max = ips.iface_index;
|
||||
udev->ifaces = NULL;
|
||||
if (udev->ifaces_max != 0) {
|
||||
udev->ifaces = malloc(sizeof(*iface) * udev->ifaces_max,
|
||||
M_USB, M_WAITOK | M_ZERO);
|
||||
if (udev->ifaces == NULL) {
|
||||
err = USB_ERR_NOMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
udev->pipes_max = ep_max;
|
||||
udev->pipes = NULL;
|
||||
if (udev->pipes_max != 0) {
|
||||
udev->pipes = malloc(sizeof(*pipe) * udev->pipes_max,
|
||||
M_USB, M_WAITOK | M_ZERO);
|
||||
if (udev->pipes == NULL) {
|
||||
err = USB_ERR_NOMEM;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (err) {
|
||||
if (cmd == USB_CFG_ALLOC) {
|
||||
cleanup:
|
||||
/* cleanup */
|
||||
if (udev->ifaces != NULL)
|
||||
free(udev->ifaces, M_USB);
|
||||
if (udev->pipes != NULL)
|
||||
free(udev->pipes, M_USB);
|
||||
|
||||
udev->ifaces = NULL;
|
||||
udev->pipes = NULL;
|
||||
udev->ifaces_max = 0;
|
||||
udev->pipes_max = 0;
|
||||
}
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_set_alt_interface_index
|
||||
*
|
||||
@ -726,7 +796,8 @@ usb2_set_alt_interface_index(struct usb2_device *udev,
|
||||
goto done;
|
||||
}
|
||||
if (udev->flags.usb2_mode == USB_MODE_DEVICE) {
|
||||
usb2_detach_device(udev, iface_index, 1);
|
||||
usb2_detach_device(udev, iface_index,
|
||||
USB_UNCFG_FLAG_FREE_SUBDEV);
|
||||
} else {
|
||||
if (iface->alt_index == alt_index) {
|
||||
/*
|
||||
@ -744,7 +815,8 @@ usb2_set_alt_interface_index(struct usb2_device *udev,
|
||||
*/
|
||||
usb2_fifo_free_wrap(udev, iface_index, 0);
|
||||
#endif
|
||||
err = usb2_fill_iface_data(udev, iface_index, alt_index);
|
||||
|
||||
err = usb2_config_parse(udev, iface_index, alt_index);
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
@ -874,15 +946,17 @@ usb2_reset_iface_endpoints(struct usb2_device *udev, uint8_t iface_index)
|
||||
*
|
||||
* This function will try to detach an USB device. If it fails a panic
|
||||
* will result.
|
||||
*
|
||||
* Flag values, see "USB_UNCFG_FLAG_XXX".
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb2_detach_device_sub(struct usb2_device *udev, device_t *ppdev,
|
||||
uint8_t free_subdev)
|
||||
uint8_t flag)
|
||||
{
|
||||
device_t dev;
|
||||
int err;
|
||||
|
||||
if (!free_subdev) {
|
||||
if (!(flag & USB_UNCFG_FLAG_FREE_SUBDEV)) {
|
||||
|
||||
*ppdev = NULL;
|
||||
|
||||
@ -928,14 +1002,15 @@ usb2_detach_device_sub(struct usb2_device *udev, device_t *ppdev,
|
||||
*
|
||||
* The following function will detach the matching interfaces.
|
||||
* This function is NULL safe.
|
||||
*
|
||||
* Flag values, see "USB_UNCFG_FLAG_XXX".
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb2_detach_device(struct usb2_device *udev, uint8_t iface_index,
|
||||
uint8_t free_subdev)
|
||||
uint8_t flag)
|
||||
{
|
||||
struct usb2_interface *iface;
|
||||
uint8_t i;
|
||||
uint8_t do_unlock;
|
||||
|
||||
if (udev == NULL) {
|
||||
/* nothing to do */
|
||||
@ -943,13 +1018,7 @@ usb2_detach_device(struct usb2_device *udev, uint8_t iface_index,
|
||||
}
|
||||
DPRINTFN(4, "udev=%p\n", udev);
|
||||
|
||||
/* automatic locking */
|
||||
if (sx_xlocked(udev->default_sx + 1)) {
|
||||
do_unlock = 0;
|
||||
} else {
|
||||
do_unlock = 1;
|
||||
sx_xlock(udev->default_sx + 1);
|
||||
}
|
||||
sx_assert(udev->default_sx + 1, SA_LOCKED);
|
||||
|
||||
/*
|
||||
* First detach the child to give the child's detach routine a
|
||||
@ -974,11 +1043,7 @@ usb2_detach_device(struct usb2_device *udev, uint8_t iface_index,
|
||||
/* looks like the end of the USB interfaces */
|
||||
break;
|
||||
}
|
||||
usb2_detach_device_sub(udev, &iface->subdev, free_subdev);
|
||||
}
|
||||
|
||||
if (do_unlock) {
|
||||
sx_unlock(udev->default_sx + 1);
|
||||
usb2_detach_device_sub(udev, &iface->subdev, flag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1445,7 +1510,7 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
|
||||
}
|
||||
|
||||
/* init the default pipe */
|
||||
usb2_fill_pipe_data(udev, 0,
|
||||
usb2_init_pipe(udev, 0,
|
||||
&udev->default_ep_desc,
|
||||
&udev->default_pipe);
|
||||
|
||||
@ -1682,7 +1747,8 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
|
||||
} else if ((config_index + 1) < udev->ddesc.bNumConfigurations) {
|
||||
|
||||
if ((udev->cdesc->bNumInterface < 2) &&
|
||||
(usb2_get_no_endpoints(udev->cdesc) == 0)) {
|
||||
(usb2_get_no_descriptors(udev->cdesc,
|
||||
UDESC_ENDPOINT) == 0)) {
|
||||
DPRINTFN(0, "Found no endpoints "
|
||||
"(trying next config)!\n");
|
||||
config_index++;
|
||||
@ -1728,7 +1794,9 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus,
|
||||
done:
|
||||
if (err) {
|
||||
/* free device */
|
||||
usb2_free_device(udev);
|
||||
usb2_free_device(udev,
|
||||
USB_UNCFG_FLAG_FREE_SUBDEV |
|
||||
USB_UNCFG_FLAG_FREE_EP0);
|
||||
udev = NULL;
|
||||
}
|
||||
return (udev);
|
||||
@ -1846,14 +1914,21 @@ usb2_cdev_cleanup(void* arg)
|
||||
* usb2_free_device
|
||||
*
|
||||
* This function is NULL safe and will free an USB device.
|
||||
*
|
||||
* Flag values, see "USB_UNCFG_FLAG_XXX".
|
||||
*------------------------------------------------------------------------*/
|
||||
void
|
||||
usb2_free_device(struct usb2_device *udev)
|
||||
usb2_free_device(struct usb2_device *udev, uint8_t flag)
|
||||
{
|
||||
struct usb2_bus *bus = udev->bus;;
|
||||
struct usb2_bus *bus;
|
||||
|
||||
if (udev == NULL)
|
||||
return; /* already freed */
|
||||
|
||||
DPRINTFN(4, "udev=%p port=%d\n", udev, udev->port_no);
|
||||
|
||||
bus = udev->bus;;
|
||||
|
||||
#if USB_HAVE_UGEN
|
||||
usb2_notify_addq("-", udev);
|
||||
|
||||
@ -1882,26 +1957,18 @@ usb2_free_device(struct usb2_device *udev)
|
||||
usb2_cv_wait(udev->default_cv + 1, &usb2_ref_lock);
|
||||
}
|
||||
mtx_unlock(&usb2_ref_lock);
|
||||
|
||||
destroy_dev_sched_cb(udev->default_dev, usb2_cdev_cleanup,
|
||||
udev->default_dev->si_drv1);
|
||||
#endif
|
||||
|
||||
if (udev->flags.usb2_mode == USB_MODE_DEVICE) {
|
||||
/* stop receiving any control transfers (Device Side Mode) */
|
||||
usb2_transfer_unsetup(udev->default_xfer, USB_DEFAULT_XFER_MAX);
|
||||
}
|
||||
#if USB_HAVE_UGEN
|
||||
/* free all FIFOs */
|
||||
usb2_fifo_free_wrap(udev, USB_IFACE_INDEX_ANY, 1);
|
||||
|
||||
/*
|
||||
* Free all interface related data and FIFOs, if any.
|
||||
*/
|
||||
usb2_cdev_free(udev);
|
||||
#endif
|
||||
usb2_free_iface_data(udev);
|
||||
#if USB_HAVE_UGEN
|
||||
destroy_dev_sched_cb(udev->default_dev, usb2_cdev_cleanup,
|
||||
udev->default_dev->si_drv1);
|
||||
#endif
|
||||
/* the following will get the device unconfigured in software */
|
||||
usb2_unconfigure(udev, flag);
|
||||
|
||||
/* unsetup any leftover default USB transfers */
|
||||
usb2_transfer_unsetup(udev->default_xfer, USB_DEFAULT_XFER_MAX);
|
||||
@ -1948,12 +2015,8 @@ usb2_get_iface(struct usb2_device *udev, uint8_t iface_index)
|
||||
{
|
||||
struct usb2_interface *iface = udev->ifaces + iface_index;
|
||||
|
||||
if ((iface < udev->ifaces) ||
|
||||
(iface_index >= USB_IFACE_MAX) ||
|
||||
(udev->cdesc == NULL) ||
|
||||
(iface_index >= udev->cdesc->bNumInterface)) {
|
||||
if (iface_index >= udev->ifaces_max)
|
||||
return (NULL);
|
||||
}
|
||||
return (iface);
|
||||
}
|
||||
|
||||
@ -2303,12 +2366,12 @@ usb2_notify_addq(const char *type, struct usb2_device *udev)
|
||||
*
|
||||
* This function will free the FIFOs.
|
||||
*
|
||||
* Flag values, if "iface_index" is equal to "USB_IFACE_INDEX_ANY".
|
||||
* 0: Free all FIFOs except generic control endpoints.
|
||||
* 1: Free all FIFOs.
|
||||
*
|
||||
* Flag values, if "iface_index" is not equal to "USB_IFACE_INDEX_ANY".
|
||||
* Not used.
|
||||
* Description of "flag" argument: If the USB_UNCFG_FLAG_FREE_EP0 flag
|
||||
* is set and "iface_index" is set to "USB_IFACE_INDEX_ANY", we free
|
||||
* all FIFOs. If the USB_UNCFG_FLAG_FREE_EP0 flag is not set and
|
||||
* "iface_index" is set to "USB_IFACE_INDEX_ANY", we free all non
|
||||
* control endpoint FIFOs. If "iface_index" is not set to
|
||||
* "USB_IFACE_INDEX_ANY" the flag has no effect.
|
||||
*------------------------------------------------------------------------*/
|
||||
static void
|
||||
usb2_fifo_free_wrap(struct usb2_device *udev,
|
||||
@ -2341,7 +2404,8 @@ usb2_fifo_free_wrap(struct usb2_device *udev,
|
||||
}
|
||||
} else if (iface_index == USB_IFACE_INDEX_ANY) {
|
||||
if ((f->methods == &usb2_ugen_methods) &&
|
||||
(f->dev_ep_index == 0) && (flag == 0) &&
|
||||
(f->dev_ep_index == 0) &&
|
||||
(!(flag & USB_UNCFG_FLAG_FREE_EP0)) &&
|
||||
(f->fs_xfer == NULL)) {
|
||||
/* no need to free this FIFO */
|
||||
continue;
|
||||
|
@ -32,6 +32,18 @@ struct usb_device; /* linux compat */
|
||||
|
||||
#define USB_DEFAULT_XFER_MAX 2
|
||||
|
||||
/* "usb2_parse_config()" commands */
|
||||
|
||||
#define USB_CFG_ALLOC 0
|
||||
#define USB_CFG_FREE 1
|
||||
#define USB_CFG_INIT 2
|
||||
|
||||
/* "usb2_unconfigure()" flags */
|
||||
|
||||
#define USB_UNCFG_FLAG_NONE 0x00
|
||||
#define USB_UNCFG_FLAG_FREE_SUBDEV 0x01 /* subdevices are freed */
|
||||
#define USB_UNCFG_FLAG_FREE_EP0 0x02 /* endpoint zero is freed */
|
||||
|
||||
struct usb2_clear_stall_msg {
|
||||
struct usb2_proc_msg hdr;
|
||||
struct usb2_device *udev;
|
||||
@ -103,10 +115,9 @@ struct usb2_device {
|
||||
struct sx default_sx[2];
|
||||
struct mtx default_mtx[1];
|
||||
struct cv default_cv[2];
|
||||
struct usb2_interface ifaces[USB_IFACE_MAX];
|
||||
struct usb2_interface *ifaces;
|
||||
struct usb2_pipe default_pipe; /* Control Endpoint 0 */
|
||||
struct cdev *default_dev; /* Control Endpoint 0 device node */
|
||||
struct usb2_pipe pipes[USB_EP_MAX];
|
||||
struct usb2_pipe *pipes;
|
||||
struct usb2_power_save pwr_save;/* power save data */
|
||||
|
||||
struct usb2_bus *bus; /* our USB BUS */
|
||||
@ -123,6 +134,7 @@ struct usb2_device {
|
||||
#if USB_HAVE_UGEN
|
||||
struct usb2_fifo *fifo[USB_FIFO_MAX];
|
||||
struct usb2_symlink *ugen_symlink; /* our generic symlink */
|
||||
struct cdev *default_dev; /* Control Endpoint 0 device node */
|
||||
LIST_HEAD(,usb2_fs_privdata) pd_list;
|
||||
char ugen_name[20]; /* name of ugenX.X device */
|
||||
#endif
|
||||
@ -146,6 +158,8 @@ struct usb2_device {
|
||||
uint8_t hs_port_no; /* high-speed HUB port number */
|
||||
uint8_t driver_added_refcount; /* our driver added generation count */
|
||||
uint8_t power_mode; /* see USB_POWER_XXX */
|
||||
uint8_t ifaces_max; /* number of interfaces present */
|
||||
uint8_t pipes_max; /* number of pipes present */
|
||||
|
||||
/* the "flags" field is write-protected by "bus->mtx" */
|
||||
|
||||
@ -184,10 +198,8 @@ usb2_error_t usb2_set_endpoint_stall(struct usb2_device *udev,
|
||||
struct usb2_pipe *pipe, uint8_t do_stall);
|
||||
usb2_error_t usb2_suspend_resume(struct usb2_device *udev,
|
||||
uint8_t do_suspend);
|
||||
void usb2_detach_device(struct usb2_device *udev, uint8_t iface_index,
|
||||
uint8_t free_subdev);
|
||||
void usb2_devinfo(struct usb2_device *udev, char *dst_ptr, uint16_t dst_len);
|
||||
void usb2_free_device(struct usb2_device *udev);
|
||||
void usb2_free_device(struct usb2_device *, uint8_t);
|
||||
void *usb2_find_descriptor(struct usb2_device *udev, void *id,
|
||||
uint8_t iface_index, uint8_t type, uint8_t type_mask,
|
||||
uint8_t subtype, uint8_t subtype_mask);
|
||||
|
@ -297,8 +297,9 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
|
||||
/* detach any existing devices */
|
||||
|
||||
if (child) {
|
||||
usb2_detach_device(child, USB_IFACE_INDEX_ANY, 1);
|
||||
usb2_free_device(child);
|
||||
usb2_free_device(child,
|
||||
USB_UNCFG_FLAG_FREE_SUBDEV |
|
||||
USB_UNCFG_FLAG_FREE_EP0);
|
||||
child = NULL;
|
||||
}
|
||||
/* get fresh status */
|
||||
@ -417,8 +418,9 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
|
||||
|
||||
error:
|
||||
if (child) {
|
||||
usb2_detach_device(child, USB_IFACE_INDEX_ANY, 1);
|
||||
usb2_free_device(child);
|
||||
usb2_free_device(child,
|
||||
USB_UNCFG_FLAG_FREE_SUBDEV |
|
||||
USB_UNCFG_FLAG_FREE_EP0);
|
||||
child = NULL;
|
||||
}
|
||||
if (err == 0) {
|
||||
@ -852,9 +854,8 @@ uhub_detach(device_t dev)
|
||||
* Subdevices are not freed, because the caller of
|
||||
* uhub_detach() will do that.
|
||||
*/
|
||||
usb2_detach_device(child, USB_IFACE_INDEX_ANY, 0);
|
||||
usb2_free_device(child);
|
||||
child = NULL;
|
||||
usb2_free_device(child,
|
||||
USB_UNCFG_FLAG_FREE_EP0);
|
||||
}
|
||||
|
||||
usb2_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER);
|
||||
|
@ -84,113 +84,109 @@ usb2_desc_foreach(struct usb2_config_descriptor *cd,
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_find_idesc
|
||||
* usb2_idesc_foreach
|
||||
*
|
||||
* This function will return the interface descriptor, if any, that
|
||||
* has index "iface_index" and alternate index "alt_index".
|
||||
* 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 usb2_interface_descriptor *
|
||||
usb2_find_idesc(struct usb2_config_descriptor *cd,
|
||||
uint8_t iface_index, uint8_t alt_index)
|
||||
usb2_idesc_foreach(struct usb2_config_descriptor *cd,
|
||||
struct usb2_idesc_parse_state *ps)
|
||||
{
|
||||
struct usb2_descriptor *desc = NULL;
|
||||
struct usb2_interface_descriptor *id;
|
||||
uint8_t curidx = 0;
|
||||
uint8_t lastidx = 0;
|
||||
uint8_t curaidx = 0;
|
||||
uint8_t first = 1;
|
||||
uint8_t new_iface;
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
if ((desc->bDescriptorType == UDESC_INTERFACE) &&
|
||||
(desc->bLength >= sizeof(*id))) {
|
||||
id = (void *)desc;
|
||||
/* retrieve current descriptor */
|
||||
id = (struct usb2_interface_descriptor *)ps->desc;
|
||||
/* default is to start a new interface */
|
||||
new_iface = 1;
|
||||
|
||||
if (first) {
|
||||
first = 0;
|
||||
lastidx = id->bInterfaceNumber;
|
||||
|
||||
} else if (id->bInterfaceNumber != lastidx) {
|
||||
|
||||
lastidx = id->bInterfaceNumber;
|
||||
curidx++;
|
||||
curaidx = 0;
|
||||
|
||||
} else {
|
||||
curaidx++;
|
||||
}
|
||||
|
||||
if ((iface_index == curidx) && (alt_index == curaidx)) {
|
||||
return (id);
|
||||
}
|
||||
while (1) {
|
||||
id = (struct usb2_interface_descriptor *)
|
||||
usb2_desc_foreach(cd, (struct usb2_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;
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
|
||||
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 usb2_descriptor *)id;
|
||||
return (id);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_find_edesc
|
||||
* usb2_edesc_foreach
|
||||
*
|
||||
* This function will return the endpoint descriptor for the passed
|
||||
* interface index, alternate index and endpoint index.
|
||||
* 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 usb2_endpoint_descriptor *
|
||||
usb2_find_edesc(struct usb2_config_descriptor *cd,
|
||||
uint8_t iface_index, uint8_t alt_index, uint8_t ep_index)
|
||||
usb2_edesc_foreach(struct usb2_config_descriptor *cd,
|
||||
struct usb2_endpoint_descriptor *ped)
|
||||
{
|
||||
struct usb2_descriptor *desc = NULL;
|
||||
struct usb2_interface_descriptor *d;
|
||||
uint8_t curidx = 0;
|
||||
struct usb2_descriptor *desc;
|
||||
|
||||
d = usb2_find_idesc(cd, iface_index, alt_index);
|
||||
if (d == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (ep_index >= d->bNumEndpoints) /* quick exit */
|
||||
return (NULL);
|
||||
|
||||
desc = ((void *)d);
|
||||
desc = ((struct usb2_descriptor *)ped);
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
if (desc->bDescriptorType == UDESC_INTERFACE) {
|
||||
break;
|
||||
}
|
||||
if (desc->bDescriptorType == UDESC_ENDPOINT) {
|
||||
if (curidx == ep_index) {
|
||||
if (desc->bLength <
|
||||
sizeof(struct usb2_endpoint_descriptor)) {
|
||||
/* endpoint index is invalid */
|
||||
break;
|
||||
}
|
||||
return ((void *)desc);
|
||||
if (desc->bLength < sizeof(*ped)) {
|
||||
/* endpoint index is invalid */
|
||||
break;
|
||||
}
|
||||
curidx++;
|
||||
return ((struct usb2_endpoint_descriptor *)desc);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*
|
||||
* usb2_get_no_endpoints
|
||||
* usb2_get_no_descriptors
|
||||
*
|
||||
* This function will count the total number of endpoints available.
|
||||
* This function will count the total number of descriptors in the
|
||||
* configuration descriptor of type "type".
|
||||
*------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
usb2_get_no_endpoints(struct usb2_config_descriptor *cd)
|
||||
uint8_t
|
||||
usb2_get_no_descriptors(struct usb2_config_descriptor *cd, uint8_t type)
|
||||
{
|
||||
struct usb2_descriptor *desc = NULL;
|
||||
uint16_t count = 0;
|
||||
uint8_t count = 0;
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
if (desc->bDescriptorType == UDESC_ENDPOINT) {
|
||||
if (desc->bDescriptorType == type) {
|
||||
count++;
|
||||
if (count == 0xFF)
|
||||
break; /* crazy */
|
||||
}
|
||||
}
|
||||
return (count);
|
||||
@ -200,25 +196,30 @@ usb2_get_no_endpoints(struct usb2_config_descriptor *cd)
|
||||
* usb2_get_no_alts
|
||||
*
|
||||
* Return value:
|
||||
* Number of alternate settings for the given "ifaceno".
|
||||
*
|
||||
* NOTE: The returned can be larger than the actual number of
|
||||
* alternate settings.
|
||||
* Number of alternate settings for the given interface descriptor pointer.
|
||||
*------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno)
|
||||
uint8_t
|
||||
usb2_get_no_alts(struct usb2_config_descriptor *cd,
|
||||
struct usb2_interface_descriptor *id)
|
||||
{
|
||||
struct usb2_descriptor *desc = NULL;
|
||||
struct usb2_interface_descriptor *id;
|
||||
uint16_t n = 0;
|
||||
struct usb2_descriptor *desc;
|
||||
uint8_t n = 0;
|
||||
uint8_t ifaceno;
|
||||
|
||||
ifaceno = id->bInterfaceNumber;
|
||||
|
||||
desc = (struct usb2_descriptor *)id;
|
||||
|
||||
while ((desc = usb2_desc_foreach(cd, desc))) {
|
||||
if ((desc->bDescriptorType == UDESC_INTERFACE) &&
|
||||
(desc->bLength >= sizeof(*id))) {
|
||||
id = (void *)desc;
|
||||
id = (struct usb2_interface_descriptor *)desc;
|
||||
if (id->bInterfaceNumber == ifaceno) {
|
||||
n++;
|
||||
}
|
||||
if (n == 0xFF)
|
||||
break; /* crazy */
|
||||
} else
|
||||
break; /* end */
|
||||
}
|
||||
}
|
||||
return (n);
|
||||
|
@ -27,15 +27,28 @@
|
||||
#ifndef _USB2_PARSE_H_
|
||||
#define _USB2_PARSE_H_
|
||||
|
||||
/* structures */
|
||||
|
||||
struct usb2_idesc_parse_state {
|
||||
struct usb2_descriptor *desc;
|
||||
uint8_t iface_index; /* current interface index */
|
||||
uint8_t iface_no_last;
|
||||
uint8_t iface_index_alt; /* current alternate setting */
|
||||
};
|
||||
|
||||
/* prototypes */
|
||||
|
||||
struct usb2_descriptor *usb2_desc_foreach(struct usb2_config_descriptor *cd,
|
||||
struct usb2_descriptor *desc);
|
||||
struct usb2_interface_descriptor *usb2_find_idesc(
|
||||
struct usb2_config_descriptor *cd, uint8_t iface_index,
|
||||
uint8_t alt_index);
|
||||
struct usb2_endpoint_descriptor *usb2_find_edesc(
|
||||
struct usb2_config_descriptor *cd, uint8_t iface_index,
|
||||
uint8_t alt_index, uint8_t ep_index);
|
||||
uint16_t usb2_get_no_endpoints(struct usb2_config_descriptor *cd);
|
||||
uint16_t usb2_get_no_alts(struct usb2_config_descriptor *cd, uint8_t ifaceno);
|
||||
struct usb2_interface_descriptor *usb2_idesc_foreach(
|
||||
struct usb2_config_descriptor *cd,
|
||||
struct usb2_idesc_parse_state *ps);
|
||||
struct usb2_endpoint_descriptor *usb2_edesc_foreach(
|
||||
struct usb2_config_descriptor *cd,
|
||||
struct usb2_endpoint_descriptor *ped);
|
||||
uint8_t usb2_get_no_descriptors(struct usb2_config_descriptor *cd,
|
||||
uint8_t type);
|
||||
uint8_t usb2_get_no_alts(struct usb2_config_descriptor *cd,
|
||||
struct usb2_interface_descriptor *id);
|
||||
|
||||
#endif /* _USB2_PARSE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user