diff options
-rw-r--r-- | drivers/usb/gadget/config.c | 76 | ||||
-rw-r--r-- | drivers/usb/gadget/epautoconf.c | 1 | ||||
-rw-r--r-- | include/linux/usb/gadget.h | 19 |
3 files changed, 95 insertions, 1 deletions
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index a4e54b2743f0..1ca1c326392a 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c | |||
@@ -96,7 +96,7 @@ int usb_gadget_config_buf( | |||
96 | /* config descriptor first */ | 96 | /* config descriptor first */ |
97 | if (length < USB_DT_CONFIG_SIZE || !desc) | 97 | if (length < USB_DT_CONFIG_SIZE || !desc) |
98 | return -EINVAL; | 98 | return -EINVAL; |
99 | *cp = *config; | 99 | *cp = *config; |
100 | 100 | ||
101 | /* then interface/endpoint/class/vendor/... */ | 101 | /* then interface/endpoint/class/vendor/... */ |
102 | len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, | 102 | len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, |
@@ -115,3 +115,77 @@ int usb_gadget_config_buf( | |||
115 | return len; | 115 | return len; |
116 | } | 116 | } |
117 | 117 | ||
118 | /** | ||
119 | * usb_copy_descriptors - copy a vector of USB descriptors | ||
120 | * @src: null-terminated vector to copy | ||
121 | * Context: initialization code, which may sleep | ||
122 | * | ||
123 | * This makes a copy of a vector of USB descriptors. Its primary use | ||
124 | * is to support usb_function objects which can have multiple copies, | ||
125 | * each needing different descriptors. Functions may have static | ||
126 | * tables of descriptors, which are used as templates and customized | ||
127 | * with identifiers (for interfaces, strings, endpoints, and more) | ||
128 | * as needed by a given function instance. | ||
129 | */ | ||
130 | struct usb_descriptor_header **__init | ||
131 | usb_copy_descriptors(struct usb_descriptor_header **src) | ||
132 | { | ||
133 | struct usb_descriptor_header **tmp; | ||
134 | unsigned bytes; | ||
135 | unsigned n_desc; | ||
136 | void *mem; | ||
137 | struct usb_descriptor_header **ret; | ||
138 | |||
139 | /* count descriptors and their sizes; then add vector size */ | ||
140 | for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) | ||
141 | bytes += (*tmp)->bLength; | ||
142 | bytes += (n_desc + 1) * sizeof(*tmp); | ||
143 | |||
144 | mem = kmalloc(bytes, GFP_KERNEL); | ||
145 | if (!mem) | ||
146 | return NULL; | ||
147 | |||
148 | /* fill in pointers starting at "tmp", | ||
149 | * to descriptors copied starting at "mem"; | ||
150 | * and return "ret" | ||
151 | */ | ||
152 | tmp = mem; | ||
153 | ret = mem; | ||
154 | mem += (n_desc + 1) * sizeof(*tmp); | ||
155 | while (*src) { | ||
156 | memcpy(mem, *src, (*src)->bLength); | ||
157 | *tmp = mem; | ||
158 | tmp++; | ||
159 | mem += (*src)->bLength; | ||
160 | src++; | ||
161 | } | ||
162 | *tmp = NULL; | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * usb_find_endpoint - find a copy of an endpoint descriptor | ||
169 | * @src: original vector of descriptors | ||
170 | * @copy: copy of @src | ||
171 | * @ep: endpoint descriptor found in @src | ||
172 | * | ||
173 | * This returns the copy of the @match descriptor made for @copy. Its | ||
174 | * intended use is to help remembering the endpoint descriptor to use | ||
175 | * when enabling a given endpoint. | ||
176 | */ | ||
177 | struct usb_endpoint_descriptor *__init | ||
178 | usb_find_endpoint( | ||
179 | struct usb_descriptor_header **src, | ||
180 | struct usb_descriptor_header **copy, | ||
181 | struct usb_endpoint_descriptor *match | ||
182 | ) | ||
183 | { | ||
184 | while (*src) { | ||
185 | if (*src == (void *) match) | ||
186 | return (void *)*copy; | ||
187 | src++; | ||
188 | copy++; | ||
189 | } | ||
190 | return NULL; | ||
191 | } | ||
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 8bdad221fa91..9462e30192d8 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c | |||
@@ -159,6 +159,7 @@ ep_matches ( | |||
159 | /* MATCH!! */ | 159 | /* MATCH!! */ |
160 | 160 | ||
161 | /* report address */ | 161 | /* report address */ |
162 | desc->bEndpointAddress &= USB_DIR_IN; | ||
162 | if (isdigit (ep->name [2])) { | 163 | if (isdigit (ep->name [2])) { |
163 | u8 num = simple_strtol (&ep->name [2], NULL, 10); | 164 | u8 num = simple_strtol (&ep->name [2], NULL, 10); |
164 | desc->bEndpointAddress |= num; | 165 | desc->bEndpointAddress |= num; |
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index cf468fbdbf8e..0ebedaec075d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h | |||
@@ -858,6 +858,25 @@ int usb_descriptor_fillbuf(void *, unsigned, | |||
858 | int usb_gadget_config_buf(const struct usb_config_descriptor *config, | 858 | int usb_gadget_config_buf(const struct usb_config_descriptor *config, |
859 | void *buf, unsigned buflen, const struct usb_descriptor_header **desc); | 859 | void *buf, unsigned buflen, const struct usb_descriptor_header **desc); |
860 | 860 | ||
861 | /* copy a NULL-terminated vector of descriptors */ | ||
862 | struct usb_descriptor_header **usb_copy_descriptors( | ||
863 | struct usb_descriptor_header **); | ||
864 | |||
865 | /* return copy of endpoint descriptor given original descriptor set */ | ||
866 | struct usb_endpoint_descriptor *usb_find_endpoint( | ||
867 | struct usb_descriptor_header **src, | ||
868 | struct usb_descriptor_header **copy, | ||
869 | struct usb_endpoint_descriptor *match); | ||
870 | |||
871 | /** | ||
872 | * usb_free_descriptors - free descriptors returned by usb_copy_descriptors() | ||
873 | * @v: vector of descriptors | ||
874 | */ | ||
875 | static inline void usb_free_descriptors(struct usb_descriptor_header **v) | ||
876 | { | ||
877 | kfree(v); | ||
878 | } | ||
879 | |||
861 | /*-------------------------------------------------------------------------*/ | 880 | /*-------------------------------------------------------------------------*/ |
862 | 881 | ||
863 | /* utility wrapping a simple endpoint selection policy */ | 882 | /* utility wrapping a simple endpoint selection policy */ |