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:
Andrew Thompson 2009-04-05 18:19:52 +00:00
parent 0ed53d4515
commit bdd4120608
6 changed files with 426 additions and 335 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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_ */