aboutsummaryrefslogtreecommitdiffstats
path: root/tools/usb
diff options
context:
space:
mode:
authorMichal Nazarewicz <mina86@mina86.com>2014-08-27 16:58:47 -0400
committerFelipe Balbi <balbi@ti.com>2014-09-02 10:16:46 -0400
commitb9a4274699c6973f62979d664cbe7c9aca4f6a9a (patch)
tree30fe4bf98ef97f9884cebfe35df467e32ba12faf /tools/usb
parent51c208c746e800dba37d1a54d3c5e601630266c4 (diff)
tools: ffs-test: add compatibility code for old kernels
If ffs-test is used with a kernel prior to 3.14, which do not support the new descriptors format, it will fail when trying to write the descriptors. Add a function that converts the new descriptors to the legacy ones and use it to retry writing the descriptors using the legacy format. Also add ā€œ-lā€ flag to ffs-test which will cause the tool to never try the new format and instead immediatelly try the legacy one. This should be useful to test whether parsing of the old format still works on given 3.14+ kernel. Signed-off-by: Michal Nazarewicz <mina86@mina86.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
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);