aboutsummaryrefslogtreecommitdiffstats
path: root/tools/usb
diff options
context:
space:
mode:
Diffstat (limited to 'tools/usb')
-rw-r--r--tools/usb/ffs-test.c112
1 files changed, 107 insertions, 5 deletions
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 708d317b0f37..88d5e71be044 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -29,6 +29,7 @@
29#include <fcntl.h> 29#include <fcntl.h>
30#include <pthread.h> 30#include <pthread.h>
31#include <stdarg.h> 31#include <stdarg.h>
32#include <stdbool.h>
32#include <stdio.h> 33#include <stdio.h>
33#include <stdlib.h> 34#include <stdlib.h>
34#include <string.h> 35#include <string.h>
@@ -172,6 +173,89 @@ static const struct {
172 }, 173 },
173}; 174};
174 175
176static size_t descs_to_legacy(void **legacy, const void *descriptors_v2)
177{
178 const unsigned char *descs_end, *descs_start;
179 __u32 length, fs_count = 0, hs_count = 0, count;
180
181 /* Read v2 header */
182 {
183 const struct {
184 const struct usb_functionfs_descs_head_v2 header;
185 const __le32 counts[];
186 } __attribute__((packed)) *const in = descriptors_v2;
187 const __le32 *counts = in->counts;
188 __u32 flags;
189
190 if (le32_to_cpu(in->header.magic) !=
191 FUNCTIONFS_DESCRIPTORS_MAGIC_V2)
192 return 0;
193 length = le32_to_cpu(in->header.length);
194 if (length <= sizeof in->header)
195 return 0;
196 length -= sizeof in->header;
197 flags = le32_to_cpu(in->header.flags);
198 if (flags & ~(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
199 FUNCTIONFS_HAS_SS_DESC))
200 return 0;
201
202#define GET_NEXT_COUNT_IF_FLAG(ret, flg) do { \
203 if (!(flags & (flg))) \
204 break; \
205 if (length < 4) \
206 return 0; \
207 ret = le32_to_cpu(*counts); \
208 length -= 4; \
209 ++counts; \
210 } while (0)
211
212 GET_NEXT_COUNT_IF_FLAG(fs_count, FUNCTIONFS_HAS_FS_DESC);
213 GET_NEXT_COUNT_IF_FLAG(hs_count, FUNCTIONFS_HAS_HS_DESC);
214 GET_NEXT_COUNT_IF_FLAG(count, FUNCTIONFS_HAS_SS_DESC);
215
216 count = fs_count + hs_count;
217 if (!count)
218 return 0;
219 descs_start = (const void *)counts;
220
221#undef GET_NEXT_COUNT_IF_FLAG
222 }
223
224 /*
225 * Find the end of FS and HS USB descriptors. SS descriptors
226 * are ignored since legacy format does not support them.
227 */
228 descs_end = descs_start;
229 do {
230 if (length < *descs_end)
231 return 0;
232 length -= *descs_end;
233 descs_end += *descs_end;
234 } while (--count);
235
236 /* Allocate legacy descriptors and copy the data. */
237 {
238#pragma GCC diagnostic push
239#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
240 struct {
241 struct usb_functionfs_descs_head header;
242 __u8 descriptors[];
243 } __attribute__((packed)) *out;
244#pragma GCC diagnostic pop
245
246 length = sizeof out->header + (descs_end - descs_start);
247 out = malloc(length);
248 out->header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
249 out->header.length = cpu_to_le32(length);
250 out->header.fs_count = cpu_to_le32(fs_count);
251 out->header.hs_count = cpu_to_le32(hs_count);
252 memcpy(out->descriptors, descs_start, descs_end - descs_start);
253 *legacy = out;
254 }
255
256 return length;
257}
258
175 259
176#define STR_INTERFACE_ "Source/Sink" 260#define STR_INTERFACE_ "Source/Sink"
177 261
@@ -491,12 +575,29 @@ ep0_consume(struct thread *ignore, const void *buf, size_t nbytes)
491 return nbytes; 575 return nbytes;
492} 576}
493 577
494static void ep0_init(struct thread *t) 578static void ep0_init(struct thread *t, bool legacy_descriptors)
495{ 579{
580 void *legacy;
496 ssize_t ret; 581 ssize_t ret;
582 size_t len;
583
584 if (legacy_descriptors) {
585 info("%s: writing descriptors\n", t->filename);
586 goto legacy;
587 }
497 588
498 info("%s: writing descriptors\n", t->filename); 589 info("%s: writing descriptors (in v2 format)\n", t->filename);
499 ret = write(t->fd, &descriptors, sizeof descriptors); 590 ret = write(t->fd, &descriptors, sizeof descriptors);
591
592 if (ret < 0 && errno == EINVAL) {
593 warn("%s: new format rejected, trying legacy\n", t->filename);
594legacy:
595 len = descs_to_legacy(&legacy, &descriptors);
596 if (len) {
597 ret = write(t->fd, legacy, len);
598 free(legacy);
599 }
600 }
500 die_on(ret < 0, "%s: write: descriptors", t->filename); 601 die_on(ret < 0, "%s: write: descriptors", t->filename);
501 602
502 info("%s: writing strings\n", t->filename); 603 info("%s: writing strings\n", t->filename);
@@ -507,14 +608,15 @@ static void ep0_init(struct thread *t)
507 608
508/******************** Main **************************************************/ 609/******************** Main **************************************************/
509 610
510int main(void) 611int main(int argc, char **argv)
511{ 612{
613 bool legacy_descriptors;
512 unsigned i; 614 unsigned i;
513 615
514 /* XXX TODO: Argument parsing missing */ 616 legacy_descriptors = argc > 2 && !strcmp(argv[1], "-l");
515 617
516 init_thread(threads); 618 init_thread(threads);
517 ep0_init(threads); 619 ep0_init(threads, legacy_descriptors);
518 620
519 for (i = 1; i < sizeof threads / sizeof *threads; ++i) 621 for (i = 1; i < sizeof threads / sizeof *threads; ++i)
520 init_thread(threads + i); 622 init_thread(threads + i);