The descriptor are updated at bind-time. Provide a copy of each descriptor so they two functions of the same kind without chaning the same descriptor. At bind time we know the capabilit of the UDC and they don't change so a copy of HS descriptors is not passed if the UDC does not support HS speed. Same goes for SS. This safes a few bytes of memory. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/gadget/config.c | 39 ++++++++++++++++++++++++++++++++++++- drivers/usb/gadget/f_loopback.c | 10 +++++++--- drivers/usb/gadget/f_sourcesink.c | 10 ++++++---- include/linux/usb/gadget.h | 7 +++++++ 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index e3a9892..34e12fc 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -19,7 +19,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> - +#include <linux/usb/composite.h> /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src) return ret; } EXPORT_SYMBOL_GPL(usb_copy_descriptors); + +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss) +{ + struct usb_gadget *g = f->config->cdev->gadget; + + if (fs) { + f->fs_descriptors = usb_copy_descriptors(fs); + if (!f->fs_descriptors) + goto err; + } + if (hs && gadget_is_dualspeed(g)) { + f->hs_descriptors = usb_copy_descriptors(hs); + if (!f->hs_descriptors) + goto err; + } + if (ss && gadget_is_superspeed(g)) { + f->ss_descriptors = usb_copy_descriptors(ss); + if (!f->ss_descriptors) + goto err; + } + return 0; +err: + usb_free_all_descriptors(f); + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(usb_assign_descriptors); + +void usb_free_all_descriptors(struct usb_function *f) +{ + usb_free_descriptors(f->fs_descriptors); + usb_free_descriptors(f->hs_descriptors); + usb_free_descriptors(f->ss_descriptors); +} +EXPORT_SYMBOL_GPL(usb_free_all_descriptors); diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index aaf707e..bb39cb2 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -177,6 +177,7 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_loopback *loop = func_to_loop(f); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -204,13 +205,16 @@ autoconf_fail: hs_loop_source_desc.bEndpointAddress = fs_loop_source_desc.bEndpointAddress; hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_loopback_descs; /* support super speed hardware */ ss_loop_source_desc.bEndpointAddress = fs_loop_source_desc.bEndpointAddress; ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress; - f->ss_descriptors = ss_loopback_descs; + + ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs, + ss_loopback_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -222,6 +226,7 @@ autoconf_fail: static void loopback_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); kfree(func_to_loop(f)); } @@ -373,7 +378,6 @@ static int __init loopback_bind_config(struct usb_configuration *c) return -ENOMEM; loop->function.name = "loopback"; - loop->function.descriptors = fs_loopback_descs; loop->function.bind = loopback_bind; loop->function.unbind = loopback_unbind; loop->function.set_alt = loopback_set_alt; diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 9d8bb0a..6ef3ea2 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -319,6 +319,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) struct usb_composite_dev *cdev = c->cdev; struct f_sourcesink *ss = func_to_ss(f); int id; + int ret; /* allocate interface ID(s) */ id = usb_interface_id(c, f); @@ -406,8 +407,6 @@ no_iso: hs_iso_sink_desc.bInterval = isoc_interval; hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_source_sink_descs; - /* support super speed hardware */ ss_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; @@ -436,7 +435,10 @@ no_iso: isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress; - f->ss_descriptors = ss_source_sink_descs; + ret = usb_assign_descriptors(f, fs_source_sink_descs, hs_source_sink_descs, + ss_source_sink_descs); + if (ret) + return ret; DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : @@ -450,6 +452,7 @@ no_iso: static void sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) { + usb_free_all_descriptors(f); kfree(func_to_ss(f)); } @@ -765,7 +768,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c) return -ENOMEM; ss->function.name = "source/sink"; - ss->function.descriptors = fs_source_sink_descs; ss->function.bind = sourcesink_bind; ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 5b6e508..0af6569 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -939,6 +939,13 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v) kfree(v); } +struct usb_function; +int usb_assign_descriptors(struct usb_function *f, + struct usb_descriptor_header **fs, + struct usb_descriptor_header **hs, + struct usb_descriptor_header **ss); +void usb_free_all_descriptors(struct usb_function *f); + /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html