Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Fri, Oct 09, 2015 at 04:19:57PM -0500, Felipe Balbi wrote: > > Signed-off-by: Christoph Hellwig> > Reviewed-by: Andrzej Pietrasiewicz > > I suppose this depends on other fs/configfs changes ? The whole series should be applied in order, but doesn't have any other dependencies. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
Hi, Christoph Hellwigwrites: > To simplify the configfs interface and remove boilerplate code that also > causes binary bloat. > > Signed-off-by: Christoph Hellwig > Reviewed-by: Andrzej Pietrasiewicz I suppose this depends on other fs/configfs changes ? -- balbi signature.asc Description: PGP signature
[PATCH 02/23] usb-gadget: use per-attribute show and store methods
To simplify the configfs interface and remove boilerplate code that also causes binary bloat. Signed-off-by: Christoph HellwigReviewed-by: Andrzej Pietrasiewicz --- drivers/usb/gadget/configfs.c | 295 ++-- include/linux/usb/gadget_configfs.h | 19 +-- 2 files changed, 118 insertions(+), 196 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 294eb74..163d305 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -64,6 +64,11 @@ struct gadget_info { char qw_sign[OS_STRING_QW_SIGN_LEN]; }; +static inline struct gadget_info *to_gadget_info(struct config_item *item) +{ +return container_of(to_config_group(item), struct gadget_info, group); +} + struct config_usb_cfg { struct config_group group; struct config_group strings_group; @@ -74,6 +79,12 @@ struct config_usb_cfg { struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; }; +static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) +{ + return container_of(to_config_group(item), struct config_usb_cfg, + group); +} + struct gadget_strings { struct usb_gadget_strings stringtab_dev; struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; @@ -117,32 +128,25 @@ static int usb_string_copy(const char *s, char **s_copy) return 0; } -CONFIGFS_ATTR_STRUCT(gadget_info); -CONFIGFS_ATTR_STRUCT(config_usb_cfg); - -#define GI_DEVICE_DESC_ITEM_ATTR(name) \ - static struct gadget_info_attribute gadget_cdev_desc_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - gadget_dev_desc_##name##_show, \ - gadget_dev_desc_##name##_store) - #define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \ + return sprintf(page, "0x%02x\n", \ + to_gadget_info(item)->cdev.desc.__name); \ } #define GI_DEVICE_DESC_SIMPLE_R_u16(__name)\ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%04x\n", le16_to_cpup(>cdev.desc.__name)); \ + return sprintf(page, "0x%04x\n", \ + le16_to_cpup(_gadget_info(item)->cdev.desc.__name)); \ } #define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u8 val; \ @@ -150,12 +154,12 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou8(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = val; \ + to_gadget_info(item)->cdev.desc._name = val;\ return len; \ } #define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u16 val;\ @@ -163,7 +167,7 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou16(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = cpu_to_le16p(); \ + to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(); \ return len; \ } @@ -193,7 +197,7 @@ static ssize_t is_valid_bcd(u16 bcd_val) return 0; } -static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item, const char *page, size_t len) { u16 bcdDevice; @@ -206,11 +210,11 @@ static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, if (ret) return ret; - gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); + to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); return len; } -static ssize_t
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
Hi, On Mon, Sep 28, 2015 at 03:33:28PM +0200, Christoph Hellwig wrote: > The Subject line is part of the commit log. If you have a useful heh > suggestion for improving the logs please feel free to suggest it. how about explaining why you want per-attribute show/store methods ? -- balbi signature.asc Description: PGP signature
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Wed, Sep 30, 2015 at 12:20:46PM -0400, Tejun Heo wrote: > On Wed, Sep 30, 2015 at 11:19:25AM -0500, Felipe Balbi wrote: > > On Mon, Sep 28, 2015 at 03:35:14PM +0200, Christoph Hellwig wrote: > > > On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > > > > this (and the other helper below) could be macros just fine. > > > > > > They could, but they shouldn't. Inlines are always preferable over > > > function-like macros. > > > > says who ? And why ? > > Documentation/CodingStyle container_of() is type-safe, what is an inline function bringing as benefit ? -- balbi signature.asc Description: PGP signature
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Wed, Sep 30, 2015 at 11:32:19AM -0500, Felipe Balbi wrote: > On Wed, Sep 30, 2015 at 12:20:46PM -0400, Tejun Heo wrote: > > On Wed, Sep 30, 2015 at 11:19:25AM -0500, Felipe Balbi wrote: > > > On Mon, Sep 28, 2015 at 03:35:14PM +0200, Christoph Hellwig wrote: > > > > On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > > > > > this (and the other helper below) could be macros just fine. > > > > > > > > They could, but they shouldn't. Inlines are always preferable over > > > > function-like macros. > > > > > > says who ? And why ? > > > > Documentation/CodingStyle > > container_of() is type-safe, what is an inline function bringing as benefit ? It's a general preference. Because there's enough benefit to going with inline functions and there's extra benefit to be gained from having consistent style of code and documentation, as a general rule, we prefer inline functions over macros. If you have specific technical arguments why macro is better, sure; otherwise, follow the conventions for consistency if for nothing else. -- tejun -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Wed, Sep 30, 2015 at 12:35:38PM -0400, Tejun Heo wrote: > On Wed, Sep 30, 2015 at 11:32:19AM -0500, Felipe Balbi wrote: > > On Wed, Sep 30, 2015 at 12:20:46PM -0400, Tejun Heo wrote: > > > On Wed, Sep 30, 2015 at 11:19:25AM -0500, Felipe Balbi wrote: > > > > On Mon, Sep 28, 2015 at 03:35:14PM +0200, Christoph Hellwig wrote: > > > > > On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > > > > > > this (and the other helper below) could be macros just fine. > > > > > > > > > > They could, but they shouldn't. Inlines are always preferable over > > > > > function-like macros. > > > > > > > > says who ? And why ? > > > > > > Documentation/CodingStyle > > > > container_of() is type-safe, what is an inline function bringing as benefit > > ? > > It's a general preference. Because there's enough benefit to going > with inline functions and there's extra benefit to be gained from > having consistent style of code and documentation, as a general rule, > we prefer inline functions over macros. If you have specific > technical arguments why macro is better, sure; otherwise, follow the > conventions for consistency if for nothing else. $ git grep -e "define.*container_of" | wc -l 1003 Seems like there are *ton* of uses of container_of() wrapped within a simple macro. What convention are you talking about, again ? And again, what benefit is an inline function bringing in this specific case ? As for a technical reason, we know the macro definition will be copied Verbatim into the caller body. GCC might decide to not inline those helpers (unlikely, but could). -- balbi signature.asc Description: PGP signature
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Wed, Sep 30, 2015 at 11:19:25AM -0500, Felipe Balbi wrote: > On Mon, Sep 28, 2015 at 03:35:14PM +0200, Christoph Hellwig wrote: > > On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > > > this (and the other helper below) could be macros just fine. > > > > They could, but they shouldn't. Inlines are always preferable over > > function-like macros. > > says who ? And why ? Documentation/CodingStyle -- tejun -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Mon, Sep 28, 2015 at 03:35:14PM +0200, Christoph Hellwig wrote: > On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > > this (and the other helper below) could be macros just fine. > > They could, but they shouldn't. Inlines are always preferable over > function-like macros. says who ? And why ? -- balbi signature.asc Description: PGP signature
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Wed, Sep 30, 2015 at 11:43:01AM -0500, Felipe Balbi wrote: > Seems like there are *ton* of uses of container_of() wrapped within a simple > macro. What convention are you talking about, again ? The convention of using inline functions over macros when possible. We don't do that all the time but that's where we wanna be in general. > And again, what benefit is an inline function bringing in this specific > case ? As for a technical reason, we know the macro definition will be > copied Verbatim into the caller body. GCC might decide to not inline > those helpers (unlikely, but could). That's really grasping at straws. Let's not go there. For simple stuff like container_of(), a more valid reason would be "it's shorter and sweeter and AFAICS doesn't have any known downsides of using macros" but this ultimately is a bike-shedding problem. You asked where and why we said we prefer inline functions so that's the answer (aside from individual technical advantages). It's not an absolute rule but we're better off if we try to keep things consistent if possible. As for this specific case, I don't know. I might do the macro too just because it's less typing and I don't really care but at the same time I'd just switch to inline if somebody points it out. -- tejun -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
W dniu 25.09.2015 o 15:49, Christoph Hellwig pisze: Signed-off-by: Christoph HellwigReviewed-by: Andrzej Pietrasiewicz --- drivers/usb/gadget/configfs.c | 295 ++-- include/linux/usb/gadget_configfs.h | 19 +-- 2 files changed, 118 insertions(+), 196 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 294eb74..163d305 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -64,6 +64,11 @@ struct gadget_info { char qw_sign[OS_STRING_QW_SIGN_LEN]; }; +static inline struct gadget_info *to_gadget_info(struct config_item *item) +{ +return container_of(to_config_group(item), struct gadget_info, group); +} + struct config_usb_cfg { struct config_group group; struct config_group strings_group; @@ -74,6 +79,12 @@ struct config_usb_cfg { struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; }; +static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) +{ + return container_of(to_config_group(item), struct config_usb_cfg, + group); +} + struct gadget_strings { struct usb_gadget_strings stringtab_dev; struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; @@ -117,32 +128,25 @@ static int usb_string_copy(const char *s, char **s_copy) return 0; } -CONFIGFS_ATTR_STRUCT(gadget_info); -CONFIGFS_ATTR_STRUCT(config_usb_cfg); - -#define GI_DEVICE_DESC_ITEM_ATTR(name) \ - static struct gadget_info_attribute gadget_cdev_desc_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - gadget_dev_desc_##name##_show, \ - gadget_dev_desc_##name##_store) - #define GI_DEVICE_DESC_SIMPLE_R_u8(__name)\ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%02x\n", gi->cdev.desc.__name);\ + return sprintf(page, "0x%02x\n", \ + to_gadget_info(item)->cdev.desc.__name); \ } #define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%04x\n", le16_to_cpup(>cdev.desc.__name)); \ + return sprintf(page, "0x%04x\n", \ + le16_to_cpup(_gadget_info(item)->cdev.desc.__name)); \ } #define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u8 val; \ @@ -150,12 +154,12 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou8(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = val; \ + to_gadget_info(item)->cdev.desc._name = val; \ return len; \ } #define GI_DEVICE_DESC_SIMPLE_W_u16(_name)\ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u16 val;\ @@ -163,7 +167,7 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou16(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = cpu_to_le16p();\ + to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(); \ return len; \ } @@ -193,7 +197,7 @@ static ssize_t is_valid_bcd(u16 bcd_val) return 0; } -static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item, const char *page, size_t len) { u16 bcdDevice; @@ -206,11 +210,11 @@ static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, if (ret) return ret; - gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); + to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); return len; } -static ssize_t gadget_dev_desc_bcdUSB_store(struct
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
The Subject line is part of the commit log. If you have a useful suggestion for improving the logs please feel free to suggest it. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Sun, Sep 27, 2015 at 10:50:53AM -0500, Felipe Balbi wrote: > this (and the other helper below) could be macros just fine. They could, but they shouldn't. Inlines are always preferable over function-like macros. > Are you 100% compiler > will *always* inline these helpers. With gcc you can't ever be sure - but if it doesn't inline a trivial pointer arithmetic we'll see breakage in various other places, including the file system fast path which uses this pattern all over. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Fri, Sep 25, 2015 at 06:49:39AM -0700, Christoph Hellwig wrote: > Signed-off-by: Christoph Hellwig> --- > drivers/usb/gadget/configfs.c | 295 > ++-- > include/linux/usb/gadget_configfs.h | 19 +-- > 2 files changed, 118 insertions(+), 196 deletions(-) > > diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c > index 294eb74..163d305 100644 > --- a/drivers/usb/gadget/configfs.c > +++ b/drivers/usb/gadget/configfs.c > @@ -64,6 +64,11 @@ struct gadget_info { > char qw_sign[OS_STRING_QW_SIGN_LEN]; > }; > > +static inline struct gadget_info *to_gadget_info(struct config_item *item) > +{ > + return container_of(to_config_group(item), struct gadget_info, group); > +} this (and the other helper below) could be macros just fine. Are you 100% compiler will *always* inline these helpers. The likelyhood of not inlining is minimal, sure, but what do we get for writing these as functions instead of macros ? also, lacking commit log -- balbi signature.asc Description: PGP signature
Re: [PATCH 02/23] usb-gadget: use per-attribute show and store methods
On Fri, Sep 25, 2015 at 06:49:39AM -0700, Christoph Hellwig wrote: > Signed-off-by: Christoph HellwigI need commit logs for everything. Without commit logs, I can't apply your patches. -- balbi signature.asc Description: PGP signature
[PATCH 02/23] usb-gadget: use per-attribute show and store methods
Signed-off-by: Christoph Hellwig--- drivers/usb/gadget/configfs.c | 295 ++-- include/linux/usb/gadget_configfs.h | 19 +-- 2 files changed, 118 insertions(+), 196 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 294eb74..163d305 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -64,6 +64,11 @@ struct gadget_info { char qw_sign[OS_STRING_QW_SIGN_LEN]; }; +static inline struct gadget_info *to_gadget_info(struct config_item *item) +{ +return container_of(to_config_group(item), struct gadget_info, group); +} + struct config_usb_cfg { struct config_group group; struct config_group strings_group; @@ -74,6 +79,12 @@ struct config_usb_cfg { struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; }; +static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) +{ + return container_of(to_config_group(item), struct config_usb_cfg, + group); +} + struct gadget_strings { struct usb_gadget_strings stringtab_dev; struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; @@ -117,32 +128,25 @@ static int usb_string_copy(const char *s, char **s_copy) return 0; } -CONFIGFS_ATTR_STRUCT(gadget_info); -CONFIGFS_ATTR_STRUCT(config_usb_cfg); - -#define GI_DEVICE_DESC_ITEM_ATTR(name) \ - static struct gadget_info_attribute gadget_cdev_desc_##name = \ - __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ - gadget_dev_desc_##name##_show, \ - gadget_dev_desc_##name##_store) - #define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \ + return sprintf(page, "0x%02x\n", \ + to_gadget_info(item)->cdev.desc.__name); \ } #define GI_DEVICE_DESC_SIMPLE_R_u16(__name)\ - static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \ char *page) \ { \ - return sprintf(page, "0x%04x\n", le16_to_cpup(>cdev.desc.__name)); \ + return sprintf(page, "0x%04x\n", \ + le16_to_cpup(_gadget_info(item)->cdev.desc.__name)); \ } #define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u8 val; \ @@ -150,12 +154,12 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou8(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = val; \ + to_gadget_info(item)->cdev.desc._name = val;\ return len; \ } #define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \ - static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ +static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \ const char *page, size_t len) \ { \ u16 val;\ @@ -163,7 +167,7 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg); ret = kstrtou16(page, 0, ); \ if (ret)\ return ret; \ - gi->cdev.desc._name = cpu_to_le16p(); \ + to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(); \ return len; \ } @@ -193,7 +197,7 @@ static ssize_t is_valid_bcd(u16 bcd_val) return 0; } -static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item, const char *page, size_t len) { u16 bcdDevice; @@ -206,11 +210,11 @@ static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, if (ret) return ret; - gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); + to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); return len; } -static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, +static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item, const char *page, size_t