From owner-svn-src-head@FreeBSD.ORG Sun Apr 5 18:19:59 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6902710657AE; Sun, 5 Apr 2009 18:19:59 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 8999A8FC14; Sun, 5 Apr 2009 18:19:52 +0000 (UTC) (envelope-from thompsa@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n35IJqX4027730; Sun, 5 Apr 2009 18:19:52 GMT (envelope-from thompsa@svn.freebsd.org) Received: (from thompsa@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n35IJqZu027724; Sun, 5 Apr 2009 18:19:52 GMT (envelope-from thompsa@svn.freebsd.org) Message-Id: <200904051819.n35IJqZu027724@svn.freebsd.org> From: Andrew Thompson Date: Sun, 5 Apr 2009 18:19:52 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r190730 - in head/sys/dev/usb: . controller X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 05 Apr 2009 18:20:03 -0000 Author: thompsa Date: Sun Apr 5 18:19:52 2009 New Revision: 190730 URL: http://svn.freebsd.org/changeset/base/190730 Log: 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 Modified: head/sys/dev/usb/controller/usb_controller.c head/sys/dev/usb/usb_device.c head/sys/dev/usb/usb_device.h head/sys/dev/usb/usb_hub.c head/sys/dev/usb/usb_parse.c head/sys/dev/usb/usb_parse.h Modified: head/sys/dev/usb/controller/usb_controller.c ============================================================================== --- head/sys/dev/usb/controller/usb_controller.c Sun Apr 5 18:19:42 2009 (r190729) +++ head/sys/dev/usb/controller/usb_controller.c Sun Apr 5 18:19:52 2009 (r190730) @@ -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); Modified: head/sys/dev/usb/usb_device.c ============================================================================== --- head/sys/dev/usb/usb_device.c Sun Apr 5 18:19:42 2009 (r190729) +++ head/sys/dev/usb/usb_device.c Sun Apr 5 18:19:52 2009 (r190730) @@ -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 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 *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 * 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 *ud } /*------------------------------------------------------------------------* - * usb2_fill_iface_data + * usb2_unconfigure + * + * This function will free all USB interfaces and USB pipes belonging + * to an USB device. * - * 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. + * Flag values, see "USB_UNCFG_FLAG_XXX". *------------------------------------------------------------------------*/ -static usb2_error_t -usb2_fill_iface_data(struct usb2_device *udev, - uint8_t iface_index, uint8_t alt_index) +static void +usb2_unconfigure(struct usb2_device *udev, uint8_t flag) { - 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; + uint8_t do_unlock; - if (iface == NULL) { - return (USB_ERR_INVAL); + /* automatic locking */ + if (sx_xlocked(udev->default_sx + 1)) { + do_unlock = 0; + } else { + do_unlock = 1; + sx_xlock(udev->default_sx + 1); } - 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++; - } + /* detach all interface drivers */ + usb2_detach_device(udev, USB_IFACE_INDEX_ANY, flag); - pipe = &udev->pipes[0]; +#if USB_HAVE_UGEN + /* free all FIFOs except control endpoint FIFOs */ + usb2_fifo_free_wrap(udev, USB_IFACE_INDEX_ANY, flag); - 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. + * Free all cdev's, 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 - * - * This function will free all USB interfaces and USB pipes belonging - * to an USB device. - *------------------------------------------------------------------------*/ -static void -usb2_free_iface_data(struct usb2_device *udev) -{ - struct usb2_interface *iface = udev->ifaces; - struct usb2_interface *iface_end = udev->ifaces + USB_IFACE_MAX; - - /* mtx_assert() */ + 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->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 /* 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 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 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->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 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 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); @@ -693,6 +564,205 @@ done: } /*------------------------------------------------------------------------* + * 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 * * This function will select an alternate interface index for the @@ -726,7 +796,8 @@ usb2_set_alt_interface_index(struct usb2 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 */ 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_d * * 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 @@ error: * * 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 *u } 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 *u /* 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, s } /* 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 @@ repeat_set_config: } 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 @@ repeat_set_config: 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 *ude 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, { 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, struc * * 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 * } } 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; Modified: head/sys/dev/usb/usb_device.h ============================================================================== --- head/sys/dev/usb/usb_device.h Sun Apr 5 18:19:42 2009 (r190729) +++ head/sys/dev/usb/usb_device.h Sun Apr 5 18:19:52 2009 (r190730) @@ -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(str 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); Modified: head/sys/dev/usb/usb_hub.c ============================================================================== --- head/sys/dev/usb/usb_hub.c Sun Apr 5 18:19:42 2009 (r190729) +++ head/sys/dev/usb/usb_hub.c Sun Apr 5 18:19:52 2009 (r190730) @@ -297,8 +297,9 @@ repeat: /* 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 @@ repeat: 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); Modified: head/sys/dev/usb/usb_parse.c ============================================================================== --- head/sys/dev/usb/usb_parse.c Sun Apr 5 18:19:42 2009 (r190729) +++ head/sys/dev/usb/usb_parse.c Sun Apr 5 18:19:52 2009 (r190730) @@ -84,113 +84,109 @@ usb2_desc_foreach(struct usb2_config_des } /*------------------------------------------------------------------------* - * 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; - - while ((desc = usb2_desc_foreach(cd, desc))) { - if ((desc->bDescriptorType == UDESC_INTERFACE) && - (desc->bLength >= sizeof(*id))) { - id = (void *)desc; - - if (first) { - first = 0; - lastidx = id->bInterfaceNumber; - - } else if (id->bInterfaceNumber != lastidx) { + uint8_t new_iface; - lastidx = id->bInterfaceNumber; - curidx++; - curaidx = 0; - - } else { - curaidx++; - } - - if ((iface_index == curidx) && (alt_index == curaidx)) { - return (id); - } + /* retrieve current descriptor */ + id = (struct usb2_interface_descriptor *)ps->desc; + /* default is to start a new interface */ + new_iface = 1; + + 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); } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***