From 8a1d6c9ed8270128948f2c2e0da8630dd114b89a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 09:07:52 -0600 Subject: [PATCH 1/8] Basic framework that might be used to add USB host support --- drivers/usbhost/Kconfig | 6 ++ drivers/usbhost/Make.defs | 4 + drivers/usbhost/usbhost_composite.c | 146 ++++++++++++++++++++++++++++ drivers/usbhost/usbhost_composite.h | 91 +++++++++++++++++ drivers/usbhost/usbhost_enumerate.c | 35 +++++-- 5 files changed, 276 insertions(+), 6 deletions(-) create mode 100644 drivers/usbhost/usbhost_composite.c create mode 100644 drivers/usbhost/usbhost_composite.h diff --git a/drivers/usbhost/Kconfig b/drivers/usbhost/Kconfig index e8768896901..ee8a1d8d5aa 100644 --- a/drivers/usbhost/Kconfig +++ b/drivers/usbhost/Kconfig @@ -77,6 +77,12 @@ config USBHOST_HUB_POLLMSEC endif # USBHOST_HUB +config USBHOST_COMPOSITE + bool "Composite device support" + default n + ---help--- + Build in USB host support for connected composite devices + config USBHOST_MSC bool "Mass Storage Class Support" default n diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs index 0391dd33390..fd28be8766f 100644 --- a/drivers/usbhost/Make.defs +++ b/drivers/usbhost/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_USBHOST_HUB),y) CSRCS += usbhost_hub.c endif +ifeq ($(CONFIG_USBHOST_COMPOSITE),y) +CSRCS += usbhost_composite.c +endif + ifeq ($(CONFIG_USBHOST_MSC),y) CSRCS += usbhost_storage.c endif diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c new file mode 100644 index 00000000000..777b90fc219 --- /dev/null +++ b/drivers/usbhost/usbhost_composite.c @@ -0,0 +1,146 @@ +/**************************************************************************** + * drivers/usbhost/usbhost_composite.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "usbhost_composite.h" + +#ifdef CONFIG_USBHOST_COMPOSITE + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: usbhost_composite + * + * Description: + * As the final steps in the device enumeration sequence this function + * will be called in order to determine (1) determine if the device is + * a composite device, and if so, (2) create the composite class which + * contains all of the individual class instances making up the composite. + * + * Input Parameters: + * hport - The downstream port to which the (potential) composite + * device has been connected. + * configdesc - The full configuration descriptor + * desclen - The length of the configuration descriptor + * devclass - If the class driver for the device is successful located + * and bound to the hub port, the allocated class instance + * is returned into this caller-provided memory location. + * + * Returned Value: + * Zero (OK) is returned if (1) the device was determined to be a + * composite device and (2) the composite class wrapper was sucessfully + * created and bound to the HCD. A negated errno value is returned on + * any failure. The value -ENOENT, in particular means that the attached + * device is not a composite device. Other values would indicate other + * various, unexpected failures. + * + ****************************************************************************/ + +int usbhost_composite(FAR struct usbhost_hubport_s *hport, + FAR const uint8_t *configdesc, int desclen, + FAR struct usbhost_id_s *id, + FAR struct usbhost_class_s **devclass) +{ + /* Determine if this a composite device has been connected to the + * downstream port. + */ + + /* Count the number of interfaces. Scan for IAD descriptors that will be + * used when it is necessary to associate multiple interfaces with a single + * device. + */ + + /* Allocate the composite class container */ + + /* Loop, processing each device that we discovered */ + /* See usbhost_classbind() for similar logic */ + + /* Is there is a class implementation registered to support this device. */ + + /* Yes.. there is a class for this device. Get an instance of + * its interface. + */ + + /* Then bind the newly instantiated class instance to the + * composite wrapper (not the HCD) */ + + /* On failures, call the class disconnect method which + * should then free the allocated devclass instance. + */ + + /* All classes have been found, instantiated and boud the the composite class + * container. Now bind the composite class instance to the HCD */ + + /* On failures, call the class disconnect method which should then free + * the allocated devclass instance. + */ + + return -ENOSYS; +} + +#endif /* CONFIG_USBHOST_COMPOSITE */ diff --git a/drivers/usbhost/usbhost_composite.h b/drivers/usbhost/usbhost_composite.h new file mode 100644 index 00000000000..8395690d47d --- /dev/null +++ b/drivers/usbhost/usbhost_composite.h @@ -0,0 +1,91 @@ +/**************************************************************************** + * drivers/usbhost/usbdev_composite.h + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_USBHOST_USBHOST_COMPOSITE_H +#define __DRIVERS_USBHOST_USBHOST_COMPOSITE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#ifdef CONFIG_USBHOST_COMPOSITE + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: usbhost_composite + * + * Description: + * As the final steps in the device enumeration sequence this function + * will be called in order to determine (1) determine if the device is + * a composite device, and if so, (2) create the composite class which + * contains all of the individual class instances making up the composite. + * + * Input Parameters: + * hport - The downstream port to which the (potential) composite + * device has been connected. + * configdesc - The full configuration descriptor + * desclen - The length of the configuration descriptor + * devclass - If the class driver for the device is successful located + * and bound to the hub port, the allocated class instance + * is returned into this caller-provided memory location. + * + * Returned Value: + * Zero (OK) is returned if (1) the device was determined to be a + * composite device and (2) the composite class wrapper was sucessfully + * created and bound to the HCD. A negated errno value is returned on + * any failure. The value -ENOENT, in particular means that the attached + * device is not a composite device. Other values would indicate other + * various, unexpected failures. + * + ****************************************************************************/ + +int usbhost_composite(FAR struct usbhost_hubport_s *hport, + FAR const uint8_t *configdesc, int desclen, + FAR struct usbhost_class_s **devclass); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* CONFIG_USBHOST_COMPOSITE */ +#endif /* #define __DRIVERS_USBHOST_USBHOST_COMPOSITE_H */ diff --git a/drivers/usbhost/usbhost_enumerate.c b/drivers/usbhost/usbhost_enumerate.c index b92c0e6fc92..c1223c4a77f 100644 --- a/drivers/usbhost/usbhost_enumerate.c +++ b/drivers/usbhost/usbhost_enumerate.c @@ -539,15 +539,38 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, usleep(100*1000); - /* Parse the configuration descriptor and bind to the class instance for the - * device. This needs to be the last thing done because the class driver - * will begin configuring the device. +#ifdef CONFIG_USBHOST_COMPOSITE + /* Check if the device attached to the downstream port if a USB composite + * device and, if so, create the composite device wrapper and bind it to + * the HCD. + * + * usbhost_composite() will return a negated errno value is on any + * failure. The value -ENOENT, in particular means that the attached + * device is not a composite device. Other values would indicate other + * various, unexpected failures. We make no real distinction here. */ - ret = usbhost_classbind(hport, buffer, cfglen, &id, devclass); - if (ret < 0) + ret = usbhost_composite(hport, buffer, cfglen, devclass); + if (ret >= 0) { - uerr("ERROR: usbhost_classbind failed %d\n", ret); + uinfo("usbhost_composite has bound the composite device\n"); + } + + /* Apparently this is not a composite device */ + + else +#endif + { + /* Parse the configuration descriptor and bind to the class instance + * for the device. This needs to be the last thing done because the + * class driver will begin configuring the device. + */ + + ret = usbhost_classbind(hport, buffer, cfglen, &id, devclass); + if (ret < 0) + { + uerr("ERROR: usbhost_classbind failed %d\n", ret); + } } errout: From 579e338cd31576fc1ddb94e715f1142b76f0c013 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 09:47:38 -0600 Subject: [PATCH 2/8] Add a little more meat to the USB host composite skeleton. Still pretty bony. --- drivers/usbhost/usbhost_composite.c | 186 ++++++++++++++++++++++++++-- 1 file changed, 176 insertions(+), 10 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index 777b90fc219..245b3dcff94 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -39,6 +39,9 @@ #include +#include +#include + #include #include "usbhost_composite.h" @@ -53,10 +56,48 @@ * Private Types ****************************************************************************/ +/* This structure describes one component class of the composite */ + +struct usbhost_component_s +{ + /* To be determined */ +}; + +/* This structure contains the internal, private state of the USB host + * CDC/ACM class. + */ + +struct usbhsot_composite_s +{ + /* This is the externally visible portion of the state. The usbclass must + * the first element of the structure. It is then cast compatible with + * struct usbhsot_composite_s. + */ + + struct usbhost_class_s usbclass; + + /* Class specific data follows */ + + uint16_t nclasses; /* Number of component classes in the composite */ + + /* The following points to an allocated array of type struct + * usbhost_component_s. Element element of the array corresponds to one + * component class in the composite. + */ + + FAR struct usbhost_component_s *members; +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +/* struct usbhost_class_s methods */ + +static int usbhost_connect(FAR struct usbhost_class_s *usbclass, + FAR const uint8_t *configdesc, int desclen); +static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -69,6 +110,94 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: usbhost_connect + * + * Description: + * This function implements the connect() method of struct + * usbhost_class_s. This method is a callback into the class + * implementation. It is used to provide the device's configuration + * descriptor to the class so that the class may initialize properly + * + * Input Parameters: + * usbclass - The USB host class entry previously obtained from a call to + * create(). + * configdesc - A pointer to a uint8_t buffer container the configuration + * descriptor. + * desclen - The length in bytes of the configuration descriptor. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value is + * returned indicating the nature of the failure + * + * NOTE that the class instance remains valid upon return with a failure. It is + * the responsibility of the higher level enumeration logic to call + * CLASS_DISCONNECTED to free up the class driver resources. + * + * Assumptions: + * - This function will *not* be called from an interrupt handler. + * - If this function returns an error, the USB host controller driver + * must call to DISCONNECTED method to recover from the error + * + ****************************************************************************/ + +static int usbhost_connect(FAR struct usbhost_class_s *usbclass, + FAR const uint8_t *configdesc, int desclen) +{ + FAR struct usbhsot_composite_s *priv = (FAR struct usbhsot_composite_s *)usbclass; + int ret; + + DEBUGASSERT(priv != NULL && + configdesc != NULL && + desclen >= sizeof(struct usb_cfgdesc_s)); + + /* Get exclusive access to the device structure */ + + /* Forward the connection information to each contained class in the + * composite + */ + + return ret; +} + +/**************************************************************************** + * Name: usbhost_disconnected + * + * Description: + * This function implements the disconnected() method of struct + * usbhost_class_s. This method is a callback into the class + * implementation. It is used to inform the class that the USB device has + * been disconnected. + * + * Input Parameters: + * usbclass - The USB host class entry previously obtained from a call to + * create(). + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function may be called from an interrupt handler. + * + ****************************************************************************/ + +static int usbhost_disconnected(struct usbhost_class_s *usbclass) +{ + FAR struct usbhsot_composite_s *priv = (FAR struct usbhsot_composite_s *)usbclass; + + DEBUGASSERT(priv != NULL); + + /* Get exclusive access to the device structure */ + + /* Forward the disconnect event to each contained class in the composite. */ + + /* Destroy the composite container */ + + kmm_free(priv); + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -106,6 +235,11 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, FAR struct usbhost_id_s *id, FAR struct usbhost_class_s **devclass) { + FAR struct usbhsot_composite_s *priv; + FAR struct usbhost_component_s *member; + uint16_t nclasses; + int i; + /* Determine if this a composite device has been connected to the * downstream port. */ @@ -117,21 +251,53 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, /* Allocate the composite class container */ + priv = (FAR struct usbhsot_composite_s *) + kmm_zalloc(sizeof(struct usbhsot_composite_s)); + + if (priv == NULL) + { + uerr("ERROR: Failed to allocate class container\n") + return -ENOMEM; + } + + priv->members = (FAR struct usbhost_component_s *) + kmm_zalloc(nclasses * sizeof(struct usbhost_component_s)); + + if (priv->members == NULL) + { + uerr("ERROR: Failed to allocate class members\n") + kmm_free(priv); + return -ENOMEM; + } + + /* Initialize the non-zero elements of the class container */ + + priv->usbclass.hport = hport; + priv->usbclass.connect = usbhost_connect; + priv->usbclass.disconnected = usbhost_disconnected; + priv->nclasses = nclasses; + /* Loop, processing each device that we discovered */ - /* See usbhost_classbind() for similar logic */ - /* Is there is a class implementation registered to support this device. */ + for (i = 0; i < nclasses; i++) + { + member = &priv->members[i]; - /* Yes.. there is a class for this device. Get an instance of - * its interface. - */ + /* See usbhost_classbind() for similar logic */ - /* Then bind the newly instantiated class instance to the - * composite wrapper (not the HCD) */ + /* Is there is a class implementation registered to support this device. */ - /* On failures, call the class disconnect method which - * should then free the allocated devclass instance. - */ + /* Yes.. there is a class for this device. Get an instance of + * its interface. + */ + + /* Then bind the newly instantiated class instance to the + * composite wrapper (not the HCD) */ + + /* On failures, call the class disconnect method which + * should then free the allocated devclass instance. + */ + } /* All classes have been found, instantiated and boud the the composite class * container. Now bind the composite class instance to the HCD */ From fa4e9e3c1cc2261f898f2c1e69c6bde190b26f63 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 10:13:35 -0600 Subject: [PATCH 3/8] Add a little more meat to the still very bony USB host composite skeleton. --- drivers/usbhost/usbhost_composite.c | 97 +++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index 245b3dcff94..ba6ba834fa3 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -60,7 +60,9 @@ struct usbhost_component_s { - /* To be determined */ + /* This the the classobject returned by each contained class */ + + FAR struct usbhost_class_s **usbclass }; /* This structure contains the internal, private state of the USB host @@ -110,6 +112,42 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass); * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: usbhost_disconnect_all + * + * Description: + * Disconnect all contained class instances. + * + * Input Parameters: + * priv - Reference to private, composite container state stucture. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void usbhost_disconnect_all(FAR struct usbhsot_composite_s *priv) +{ + FAR struct usbhost_component_s *member; + + /* Loop, processing each class that has been included into the composite */ + + for (i = 0; i < nclasses; i++) + { + member = &priv->members[i]; + + /* Has this member been included to the composite? */ + + if (member->usbclass != NULL) + { + /* Yes.. disconnect it, freeing all of the class resources */ + + CLASS_DISCONNECTED(member->usbclass); + member->usbclass = NULL; + } + } +} + /**************************************************************************** * Name: usbhost_connect * @@ -216,7 +254,7 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) * device has been connected. * configdesc - The full configuration descriptor * desclen - The length of the configuration descriptor - * devclass - If the class driver for the device is successful located + * usbclass - If the class driver for the device is successful located * and bound to the hub port, the allocated class instance * is returned into this caller-provided memory location. * @@ -233,7 +271,7 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) int usbhost_composite(FAR struct usbhost_hubport_s *hport, FAR const uint8_t *configdesc, int desclen, FAR struct usbhost_id_s *id, - FAR struct usbhost_class_s **devclass) + FAR struct usbhost_class_s **usbclass) { FAR struct usbhsot_composite_s *priv; FAR struct usbhost_component_s *member; @@ -266,8 +304,8 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, if (priv->members == NULL) { uerr("ERROR: Failed to allocate class members\n") - kmm_free(priv); - return -ENOMEM; + ret = -ENOMEM; + goto errout_with_container; } /* Initialize the non-zero elements of the class container */ @@ -295,18 +333,53 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, * composite wrapper (not the HCD) */ /* On failures, call the class disconnect method which - * should then free the allocated devclass instance. + * should then free the allocated usbclass instance. */ + + goto errout_with_members; } - /* All classes have been found, instantiated and boud the the composite class - * container. Now bind the composite class instance to the HCD */ + /* All classes have been found, instantiated and bound to the composite class + * container. Now bind the composite class continer to the HCD. + * + * REVISIT: I dont' think this is right. + */ - /* On failures, call the class disconnect method which should then free - * the allocated devclass instance. - */ + ret = CLASS_CONNECT(usbclass, configdesc, desclen); + if (ret < 0) + { + /* On failure, call the class disconnect method of each contained + * class which should then free the allocated usbclass instance. + */ - return -ENOSYS; + uerr("ERROR: CLASS_CONNECT failed: %d\n", ret); + goto errout_with_members; + } + + /* Return our USB class structure */ + + *usbclass = &priv->usbclass; + return OK; + +errout_with_members: + /* On an failure, call the class disconnect method of each contained + * class which should then free the allocated usbclass instance. + */ + + usbhost_disconnect_all(priv); + + /* Free the allocate array of composite members */ + + if (priv->members != NULL) + { + kmm_free(priv->members); + } + +errout_with_container: + /* Then free the composite container itself */ + + kmm_free(priv); + return ret; } #endif /* CONFIG_USBHOST_COMPOSITE */ From a228b0cc36dce0c8dd4cdde00afd6837ab845a8d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 10:33:41 -0600 Subject: [PATCH 4/8] Add a little more meat to the still very USB host composite skeleton. Not quite so boney now. --- drivers/usbhost/usbhost_composite.c | 37 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index ba6ba834fa3..2ff6835515f 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -189,11 +189,10 @@ static int usbhost_connect(FAR struct usbhost_class_s *usbclass, configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s)); - /* Get exclusive access to the device structure */ - /* Forward the connection information to each contained class in the * composite */ +#warning Missing logic return ret; } @@ -226,11 +225,18 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) DEBUGASSERT(priv != NULL); - /* Get exclusive access to the device structure */ - /* Forward the disconnect event to each contained class in the composite. */ - /* Destroy the composite container */ + usbhost_disconnect_all(priv); + + /* Free the allocate array of composite members */ + + if (priv->members != NULL) + { + kmm_free(priv->members); + } + + /* The destroy the composite container itself */ kmm_free(priv); return OK; @@ -281,11 +287,13 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, /* Determine if this a composite device has been connected to the * downstream port. */ +#warning Missing logic /* Count the number of interfaces. Scan for IAD descriptors that will be * used when it is necessary to associate multiple interfaces with a single * device. */ +#warning Missing logic /* Allocate the composite class container */ @@ -324,19 +332,26 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, /* See usbhost_classbind() for similar logic */ /* Is there is a class implementation registered to support this device. */ - +#warning Missing logic + { /* Yes.. there is a class for this device. Get an instance of * its interface. */ - - /* Then bind the newly instantiated class instance to the - * composite wrapper (not the HCD) */ - +#warning Missing logic + { + /* Then bind the newly instantiated class instance as an + * composite class member. + */ +#warning Missing logic + { /* On failures, call the class disconnect method which * should then free the allocated usbclass instance. */ goto errout_with_members; + } + } + } } /* All classes have been found, instantiated and bound to the composite class @@ -345,7 +360,7 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, * REVISIT: I dont' think this is right. */ - ret = CLASS_CONNECT(usbclass, configdesc, desclen); + ret = CLASS_CONNECT(&priv->usbclass, configdesc, desclen); if (ret < 0) { /* On failure, call the class disconnect method of each contained From ea8ce7acb65d058c21acb730921902e91ece6b8f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 11:05:50 -0600 Subject: [PATCH 5/8] Trivial rename --- drivers/usbhost/usbhost_composite.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.h b/drivers/usbhost/usbhost_composite.h index 8395690d47d..a44f4e7f00c 100644 --- a/drivers/usbhost/usbhost_composite.h +++ b/drivers/usbhost/usbhost_composite.h @@ -64,7 +64,7 @@ * device has been connected. * configdesc - The full configuration descriptor * desclen - The length of the configuration descriptor - * devclass - If the class driver for the device is successful located + * usbclass - If the class driver for the device is successful located * and bound to the hub port, the allocated class instance * is returned into this caller-provided memory location. * @@ -80,7 +80,7 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, FAR const uint8_t *configdesc, int desclen, - FAR struct usbhost_class_s **devclass); + FAR struct usbhost_class_s **usbclass); #undef EXTERN #if defined(__cplusplus) From 3c0b287fe91420351af388c34c7986075fcd27b5 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 12:24:35 -0600 Subject: [PATCH 6/8] Fill in a little of the 'Missing logic' in the USB host composite wrapper. --- drivers/usbhost/usbhost_composite.c | 44 ++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index 2ff6835515f..0118f25c102 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -281,6 +281,7 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, { FAR struct usbhsot_composite_s *priv; FAR struct usbhost_component_s *member; + FAR const struct usbhost_registry_s *reg; uint16_t nclasses; int i; @@ -292,6 +293,8 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, /* Count the number of interfaces. Scan for IAD descriptors that will be * used when it is necessary to associate multiple interfaces with a single * device. + * + * Save the CLASS ID information in the member structure. */ #warning Missing logic @@ -329,28 +332,31 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, { member = &priv->members[i]; - /* See usbhost_classbind() for similar logic */ + /* Is there is a class implementation registered to support this + * device. + * REVISIT: This should have been saved in member structure when the + * number of member classes was counted. + */ +#warning Missing logic to get id - /* Is there is a class implementation registered to support this device. */ -#warning Missing logic + reg = usbhost_findclass(id); + if (reg == NULL) { - /* Yes.. there is a class for this device. Get an instance of - * its interface. - */ -#warning Missing logic - { - /* Then bind the newly instantiated class instance as an - * composite class member. - */ -#warning Missing logic - { - /* On failures, call the class disconnect method which - * should then free the allocated usbclass instance. - */ + uinfo("usbhost_findclass failed\n"); + ret = -EINVAL; + goto errour_with_members; + } - goto errout_with_members; - } - } + /* Yes.. there is a class for this device. Get an instance of its + * interface. + */ + + member->usbclass = CLASS_CREATE(reg, hport, id); + if (member->usbclass == NULL) + { + uinfo("CLASS_CREATE failed\n"); + ret = -ENOMEM; + goto errour_with_members; } } From 0860621e600ba0421ef29de6e8ba6745204ad3c4 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 12:34:58 -0600 Subject: [PATCH 7/8] Fill one more case of 'Missing logic' in the USB host composite wrapper. --- drivers/usbhost/usbhost_composite.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index 0118f25c102..1c4e56315b4 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -63,6 +63,12 @@ struct usbhost_component_s /* This the the classobject returned by each contained class */ FAR struct usbhost_class_s **usbclass + + /* This is the information that we need to do the registry lookup for this + * class member. + */ + + struct usbhost_id_s id, }; /* This structure contains the internal, private state of the USB host @@ -190,7 +196,9 @@ static int usbhost_connect(FAR struct usbhost_class_s *usbclass, desclen >= sizeof(struct usb_cfgdesc_s)); /* Forward the connection information to each contained class in the - * composite + * composite. + * REVIST: Is that right? Or should it be forwarded only to the class + * matching the configdesc? I am not sure that is going on here. */ #warning Missing logic @@ -276,7 +284,6 @@ static int usbhost_disconnected(struct usbhost_class_s *usbclass) int usbhost_composite(FAR struct usbhost_hubport_s *hport, FAR const uint8_t *configdesc, int desclen, - FAR struct usbhost_id_s *id, FAR struct usbhost_class_s **usbclass) { FAR struct usbhsot_composite_s *priv; @@ -337,9 +344,8 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, * REVISIT: This should have been saved in member structure when the * number of member classes was counted. */ -#warning Missing logic to get id - reg = usbhost_findclass(id); + reg = usbhost_findclass(&priv->id); if (reg == NULL) { uinfo("usbhost_findclass failed\n"); From 2460d41ae005dac98d0b467ba0118f665322f0fc Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 26 Aug 2016 17:03:16 -0600 Subject: [PATCH 8/8] Add more logic to the USB host composite wrapper. --- drivers/usbhost/usbhost_composite.c | 88 ++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/drivers/usbhost/usbhost_composite.c b/drivers/usbhost/usbhost_composite.c index 1c4e56315b4..4d17be66871 100644 --- a/drivers/usbhost/usbhost_composite.c +++ b/drivers/usbhost/usbhost_composite.c @@ -289,21 +289,84 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, FAR struct usbhsot_composite_s *priv; FAR struct usbhost_component_s *member; FAR const struct usbhost_registry_s *reg; + FAR struct usb_desc_s *desc; + uint16_t nintfs; + uint16_t nmerged; uint16_t nclasses; + int offset; int i; /* Determine if this a composite device has been connected to the * downstream port. - */ -#warning Missing logic - - /* Count the number of interfaces. Scan for IAD descriptors that will be - * used when it is necessary to associate multiple interfaces with a single - * device. * - * Save the CLASS ID information in the member structure. + * First, count the number of interface descriptors (nintrfs) and the + * number of interfaces that are assocated to one device via IAD + * descriptor (nmerged). */ + + for (nintfs = 0, nmerged = 0, offset = 0; + offset < desclen - sizeof(struct usb_desc_s); + ) + { + desc = (FAR struct usb_desc_s *)&configdesc[offset]; + int len = desc->len; + + if (offset + len < desclen) + { + /* Is this an interface descriptor? */ + + if (desc->type == USB_DESC_TYPE_INTERFACE) + { + nintfs++; + } + + /* Check for IAD descriptors that will be used when it is + * necessary to associate multiple interfaces with a single + * device. + */ + + else if (desc->type == USB_DESC_TYPE_INTERFACEASSOCIATION) + { + FAR struct usb_iaddesc_s *iad = (FAR struct usb_iaddesc_s *)desc; + + /* Keep count of the number of merged interfaces */ + + nmerged += (iad->nifs - 1); + } + } + + offset += len; + } + + if (nintfs < 2) + { + /* Only one interface. Can't be a composite device */ + + return -ENOENT; + } + + /* Special case: Some NON-composite deveice have more than on interface: CDC/ACM + * and MSC both may have two interfaces. + */ + + if (nintfs < 3 && nmerged == 0) + { + /* Do the special case checks */ #warning Missing logic + } + + /* The total number of classes is then the number of interfaces minus the + * number of interfaces merged via the IAD descriptor. + */ + + if (nintfs <= nmerged ) + { + /* Should not happen. Means a bug. */ + + return -EINVAL; + } + + nclasses = nintfs - nmerged; /* Allocate the composite class container */ @@ -333,7 +396,16 @@ int usbhost_composite(FAR struct usbhost_hubport_s *hport, priv->usbclass.disconnected = usbhost_disconnected; priv->nclasses = nclasses; - /* Loop, processing each device that we discovered */ + /* Reparse the configuration descriptor and save the CLASS ID information + * in the member structure: If the interface is defined by an interface + * descriptor, then we have to use the info in the interface descriptor; + * If the interface has a IAD, we have to use info in the IAD. + */ +#warning Missing logic + + /* Now loop, performing the registry lookup on each class in the + * composite. + */ for (i = 0; i < nclasses; i++) {