]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/usb/slave/v2_0/tests/common.c
Initial revision
[karo-tx-redboot.git] / packages / io / usb / slave / v2_0 / tests / common.c
1 /*{{{  Banner                                                   */
2
3 /*=================================================================
4 //
5 //        common.c
6 //
7 //        USB testing - code common to host and target
8 //
9 //==========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 //
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //==========================================================================
43 //#####DESCRIPTIONBEGIN####
44 //
45 // This module contains some definitions and functions that are common to
46 // both the host and target side of USB testing, for example filling in
47 // a buffer with well-known data and validating the contents at the other end.
48 // The module is #include'd by other code rather than compiled separately,
49 // which simplifies the build process.
50 //
51 // Author(s):     bartv
52 // Date:          2001-08-14
53 //####DESCRIPTIONEND####
54 //==========================================================================
55 */
56
57 /*}}}*/
58
59 /*{{{  Simple data pack and unpack operations                   */
60
61 // ----------------------------------------------------------------------------
62 // Utilities to pack and unpack data into buffers. 
63 //
64 // Integers are transferred with 32 bits of precision, irrespective
65 // of the capabilities of either target and host.
66
67 static inline void
68 pack_int(int datum, unsigned char* buffer, int* index_ptr)
69 {
70     int index = *index_ptr;
71     buffer[index++] = (datum >>  0) & 0x0FF;
72     buffer[index++] = (datum >>  8) & 0x0FF;
73     buffer[index++] = (datum >> 16) & 0x0FF;
74     buffer[index++] = (datum >> 24) & 0x0FF;
75     *index_ptr = index;
76 }
77
78 static inline int
79 unpack_int(unsigned char* buffer, int* index_ptr)
80 {
81     int index   = *index_ptr;
82     int result;
83
84     result  = (buffer[index++] <<  0);
85     result |= (buffer[index++] <<  8);
86     result |= (buffer[index++] << 16);
87     result |= (buffer[index++] << 24);
88     *index_ptr = index;
89     return result;
90 }
91
92 /*}}}*/
93 /*{{{  Buffer data and validation                               */
94
95 // ----------------------------------------------------------------------------
96 // The data required for a given test. For some test cases, for
97 // example when trying to achieve maximum throughput, it does not
98 // matter what data is transferred. For other tests it is important to
99 // validate that the data sent and received match up, and there should
100 // be some control over the actual data: some tests might want to send
101 // a long sequence of byte 0, while others want to send more random data
102 // for which a simple random number generator is useful.
103 //
104 // Exactly the same routines are used on both host and target to fill in
105 // and check buffers, and they are sufficiently simple that the routines
106 // should get compiled in compatible ways.
107 //
108 // There is no support at present for sending specific data, e.g. a
109 // specific ethernet packet that appears to be causing problems. Knowledge
110 // of specific data cannot be compiled into the test code, so the only
111 // way to implement something like this would be to transfer the
112 // problematical data over the USB bus in order to determine whether or
113 // not the bus is capable of reliably transferring this data. That is
114 // not entirely impossible (checksums, use of alternative endpoints),
115 // but it is not implemented.
116 //
117 // An alternative approach would be to support a bounce operation
118 // involving both an IN and an OUT endpoint, doing validation only on
119 // the host. Again that is not yet implemented.
120 //
121 // The byte_fill and int_fill options are actually redundant because the
122 // same effect can be achieved using a multiplier of 1 and an increment
123 // of 0, but they can be implemented much more efficiently so may be
124 // useful for benchmarks.
125
126 typedef enum usbtestdata {
127     usbtestdata_none        = 0,       // There is nothing useful in the data
128     usbtestdata_bytefill    = 1,       // The data consists of a single byte, repeated
129     usbtestdata_wordfill    = 2,       // Or a single integer
130     usbtestdata_byteseq     = 3,       // Or a pseudo-random sequence (a * seed) + b
131     usbtestdata_wordseq     = 4        // as either bytes or integers
132 } usbtestdata;
133
134 typedef struct UsbTestData {
135     usbtestdata     format;
136     int             seed;
137     int             multiplier; // 1103515245
138     int             increment;  // 12345
139     int             transfer_seed_multiplier;
140     int             transfer_seed_increment;
141     int             transfer_multiplier_multiplier;
142     int             transfer_multiplier_increment;
143     int             transfer_increment_multiplier;
144     int             transfer_increment_increment;
145 } UsbTestData;
146
147 static void
148 usbtest_fill_buffer(UsbTestData* how, unsigned char* buffer, int length)
149 {
150     switch(how->format)
151     {
152       case usbtestdata_none:
153         return;
154         
155       case usbtestdata_bytefill:
156         // Leave it to the system to optimise memset().
157         memset(buffer, (how->seed & 0x0FF), length);
158         break;
159
160       case usbtestdata_wordfill:
161       {
162           // The buffer may not be a multiple of four bytes, so the last entry is always
163           // zero'd.
164           int i;
165           int index = 0;
166           for (i = 0; i < (length / 4); i++) {
167               pack_int(how->seed, buffer, &index);
168           }
169           pack_int(0, buffer, &index);
170           break;
171       }
172
173       case usbtestdata_byteseq:
174       {
175           int i;
176           for (i = 0; i < length; i++) {
177               buffer[i] = (how->seed & 0x00FF);
178               how->seed *= how->multiplier;
179               how->seed += how->increment;
180           }
181           break;
182       }
183
184       case usbtestdata_wordseq:
185       {
186           int i;
187           int index = 0;
188           for (i = 0; i < (length / 4); i++) {
189               pack_int(how->seed, buffer, &index);
190               how->seed *= how->multiplier;
191               how->seed += how->increment;
192           }
193           pack_int(0, buffer, &index);
194           break;
195       }
196     }
197
198     // After each transfer update the seed, multiplier and increment
199     // ready for the next one.
200     how->seed       *= how->transfer_seed_multiplier;
201     how->seed       += how->transfer_seed_increment;
202     how->multiplier *= how->transfer_multiplier_multiplier;
203     how->multiplier += how->transfer_multiplier_increment;
204     how->increment  *= how->transfer_increment_multiplier;
205     how->increment  += how->transfer_increment_increment;
206 }
207
208 static int
209 usbtest_check_buffer(UsbTestData* how, unsigned char* buffer, int length)
210 {
211     int result  = 1;
212
213     switch(how->format) {
214       case usbtestdata_none:
215         break;
216
217       case usbtestdata_bytefill:
218       {
219           int i;
220           result = 1;
221           for (i = 0; i < length; i++) {
222               if (buffer[i] != (how->seed & 0x00FF)) {
223                   result = 0;
224                   break;
225               }
226           }
227           break;
228       }
229
230       case usbtestdata_wordfill:
231       {
232           int i;
233           int index = 0;
234           for (i = 0; i < (length / 4); i++) {
235               int datum = unpack_int(buffer, &index);
236               if (datum != (how->seed & 0x0FFFFFFFF)) {
237                   result = 0;
238                   break;
239               }
240           }
241           for (i = 4 * i; result && (i < length); i++) {
242               if (0 != buffer[i]) {
243                   result = 0;
244                   break;
245               }
246           }
247           break;
248       }
249
250       case usbtestdata_byteseq:
251       {
252           int i;
253           for (i = 0; i < length; i++) {
254               if (buffer[i] != (how->seed & 0x00FF)) {
255                   result = 0;
256                   break;
257               }
258               how->seed *= how->multiplier;
259               how->seed += how->increment;
260           }
261           break;
262       }
263
264       case usbtestdata_wordseq:
265       {
266           int   i;
267           int   index = 0;
268           
269           for (i = 0; i < (length / 4); i++) {
270               int datum = unpack_int(buffer, &index);
271               if (datum != (how->seed & 0x0FFFFFFFF)) {
272                   result = 0;
273                   break;
274               }
275               how->seed *= how->multiplier;
276               how->seed += how->increment;
277           }
278           for (i = 4 * i; result && (i < length); i++) {
279               if (0 != buffer[i]) {
280                   result = 0;
281                   break;
282               }
283           }
284           break;
285       }
286     }
287
288     // After each transfer update the seed, multiplier and increment
289     // ready for the next transfer.
290     how->seed       *= how->transfer_seed_multiplier;
291     how->seed       += how->transfer_seed_increment;
292     how->multiplier *= how->transfer_multiplier_multiplier;
293     how->multiplier += how->transfer_multiplier_increment;
294     how->increment  *= how->transfer_increment_multiplier;
295     how->increment  += how->transfer_increment_increment;
296     
297     return result;
298 }
299
300 #ifdef HOST
301 static void
302 pack_usbtestdata(UsbTestData* data, unsigned char* buf, int* index)
303 {
304     pack_int((int)data->format,                         buf, index);
305     pack_int((int)data->seed,                           buf, index);
306     pack_int((int)data->multiplier,                     buf, index);
307     pack_int((int)data->increment,                      buf, index);
308     pack_int((int)data->transfer_seed_multiplier,       buf, index);
309     pack_int((int)data->transfer_seed_increment,        buf, index);
310     pack_int((int)data->transfer_multiplier_multiplier, buf, index);
311     pack_int((int)data->transfer_multiplier_increment,  buf, index);
312     pack_int((int)data->transfer_increment_multiplier,  buf, index);
313     pack_int((int)data->transfer_increment_increment,   buf, index);
314 }
315 #endif
316
317 #ifdef TARGET
318 static void
319 unpack_usbtestdata(UsbTestData* data, unsigned char* buf, int* index)
320 {
321     data->format                        = (usbtestdata) unpack_int(buf, index);
322     data->seed                          = unpack_int(buf, index);
323     data->multiplier                    = unpack_int(buf, index);
324     data->increment                     = unpack_int(buf, index);
325     data->transfer_seed_multiplier      = unpack_int(buf, index);
326     data->transfer_seed_increment       = unpack_int(buf, index);
327     data->transfer_multiplier_multiplier= unpack_int(buf, index);
328     data->transfer_multiplier_increment = unpack_int(buf, index);
329     data->transfer_increment_multiplier = unpack_int(buf, index);
330     data->transfer_increment_increment  = unpack_int(buf, index);
331 }
332 #endif
333
334 /*}}}*/
335 /*{{{  Testcase definitions                                     */
336
337 // ----------------------------------------------------------------------------
338 // Definitions of the supported test cases. The actual implementations need
339 // to vary between host and target.
340
341 typedef enum usbtest {
342     usbtest_invalid     = 0,
343     usbtest_bulk_out    = 1,
344     usbtest_bulk_in     = 2,
345     usbtest_control_in  = 3
346 } usbtest;
347
348 // What I/O mechanism should be used on the target to process data?
349 typedef enum usb_io_mechanism {
350     usb_io_mechanism_usb    = 1,        // The low-level USB-specific API
351     usb_io_mechanism_dev    = 2         // cyg_devio_cread() et al
352 } usb_io_mechanism;
353
354 // Bulk transfers. The same structure can be used for IN and OUT transfers.
355 // The endpoint number will be or'd with either USB_DIR_IN or USB_DIR_OUT,
356 // or the equivalent under eCos.
357 typedef struct UsbTest_Bulk {
358     int                 number_packets;
359     int                 endpoint;
360     int                 tx_size;
361     int                 tx_size_min;
362     int                 tx_size_max;
363     int                 tx_size_multiplier;
364     int                 tx_size_divisor;
365     int                 tx_size_increment;
366     int                 rx_size;
367     int                 rx_size_min;
368     int                 rx_size_max;
369     int                 rx_size_multiplier;
370     int                 rx_size_divisor;
371     int                 rx_size_increment;
372     int                 rx_padding;
373     int                 tx_delay;
374     int                 tx_delay_min;
375     int                 tx_delay_max;
376     int                 tx_delay_multiplier;
377     int                 tx_delay_divisor;
378     int                 tx_delay_increment;
379     int                 rx_delay;
380     int                 rx_delay_min;
381     int                 rx_delay_max;
382     int                 rx_delay_multiplier;
383     int                 rx_delay_divisor;
384     int                 rx_delay_increment;
385     usb_io_mechanism    io_mechanism;
386     UsbTestData         data;
387 } UsbTest_Bulk;
388
389 #ifdef HOST
390 static void
391 pack_usbtest_bulk(UsbTest_Bulk* test, unsigned char* buffer, int* index)
392 {
393     pack_int(test->number_packets,          buffer, index);
394     pack_int(test->endpoint,                buffer, index);
395     pack_int(test->tx_size,                 buffer, index);
396     pack_int(test->tx_size_min,             buffer, index);
397     pack_int(test->tx_size_max,             buffer, index);
398     pack_int(test->tx_size_multiplier,      buffer, index);
399     pack_int(test->tx_size_divisor,         buffer, index);
400     pack_int(test->tx_size_increment,       buffer, index);
401     pack_int(test->rx_size,                 buffer, index);
402     pack_int(test->rx_size_min,             buffer, index);
403     pack_int(test->rx_size_max,             buffer, index);
404     pack_int(test->rx_size_multiplier,      buffer, index);
405     pack_int(test->rx_size_divisor,         buffer, index);
406     pack_int(test->rx_size_increment,       buffer, index);
407     // There is no need to transfer the padding field. It is only of
408     // interest on the host, and this message is being packed
409     // for the target side.
410     pack_int(test->tx_delay,                buffer, index);
411     pack_int(test->tx_delay_min,            buffer, index);
412     pack_int(test->tx_delay_max,            buffer, index);
413     pack_int(test->tx_delay_multiplier,     buffer, index);
414     pack_int(test->tx_delay_divisor,        buffer, index);
415     pack_int(test->tx_delay_increment,      buffer, index);
416     pack_int(test->rx_delay,                buffer, index);
417     pack_int(test->rx_delay_min,            buffer, index);
418     pack_int(test->rx_delay_max,            buffer, index);
419     pack_int(test->rx_delay_multiplier,     buffer, index);
420     pack_int(test->rx_delay_divisor,        buffer, index);
421     pack_int(test->rx_delay_increment,      buffer, index);
422     pack_int((int)test->io_mechanism,       buffer, index);
423     pack_usbtestdata(&(test->data),         buffer, index);
424 }
425 #endif
426
427 #ifdef TARGET
428 static void
429 unpack_usbtest_bulk(UsbTest_Bulk* test, unsigned char* buffer, int* index)
430 {
431     test->number_packets            = unpack_int(buffer, index);
432     test->endpoint                  = unpack_int(buffer, index);
433     test->tx_size                   = unpack_int(buffer, index);
434     test->tx_size_min               = unpack_int(buffer, index);
435     test->tx_size_max               = unpack_int(buffer, index);
436     test->tx_size_multiplier        = unpack_int(buffer, index);
437     test->tx_size_divisor           = unpack_int(buffer, index);
438     test->tx_size_increment         = unpack_int(buffer, index);
439     test->rx_size                   = unpack_int(buffer, index);
440     test->rx_size_min               = unpack_int(buffer, index);
441     test->rx_size_max               = unpack_int(buffer, index);
442     test->rx_size_multiplier        = unpack_int(buffer, index);
443     test->rx_size_divisor           = unpack_int(buffer, index);
444     test->rx_size_increment         = unpack_int(buffer, index);
445     test->tx_delay                  = unpack_int(buffer, index);
446     test->tx_delay_min              = unpack_int(buffer, index);
447     test->tx_delay_max              = unpack_int(buffer, index);
448     test->tx_delay_multiplier       = unpack_int(buffer, index);
449     test->tx_delay_divisor          = unpack_int(buffer, index);
450     test->tx_delay_increment        = unpack_int(buffer, index);
451     test->rx_delay                  = unpack_int(buffer, index);
452     test->rx_delay_min              = unpack_int(buffer, index);
453     test->rx_delay_max              = unpack_int(buffer, index);
454     test->rx_delay_multiplier       = unpack_int(buffer, index);
455     test->rx_delay_divisor          = unpack_int(buffer, index);
456     test->rx_delay_increment        = unpack_int(buffer, index);
457     test->io_mechanism              = (usb_io_mechanism) unpack_int(buffer, index);
458     unpack_usbtestdata(&(test->data), buffer, index);
459 }
460 #endif
461
462 // A macro for moving on the next packet size. This also has to be shared between host
463 // and target, if the two got out of synch then testing would go horribly wrong.
464 //
465 // The new packet size is determined using a multiplier and increment,
466 // so to e.g. increase packet sizes by 4 bytes each time the
467 // multiplier would be 1 and the increment would be 4, or to double
468 // packet sizes the multiplier would be 2 and the increment would be
469 // 0. On underflow or overflow the code tries to adjust the packet size
470 // back to within the accepted range.
471
472 #define USBTEST_NEXT_TX_SIZE(_x_)                               \
473     do {                                                        \
474         _x_.tx_size *= _x_.tx_size_multiplier;                  \
475         _x_.tx_size /= _x_.tx_size_divisor;                     \
476         _x_.tx_size += _x_.tx_size_increment;                   \
477         if (_x_.tx_size < _x_.tx_size_min) {                    \
478             if (_x_.tx_size_min == _x_.tx_size_max) {           \
479                 _x_.tx_size = _x_.tx_size_min;                  \
480             } else {                                            \
481                 int tmp  = _x_.tx_size_min - _x_.tx_size;       \
482                 tmp     %= _x_.tx_size_max - _x_.tx_size_min;   \
483                 _x_.tx_size = tmp + _x_.tx_size_min;            \
484             }                                                   \
485         } else if (_x_.tx_size > _x_.tx_size_max) {             \
486             if (_x_.tx_size_min == _x_.tx_size_max) {           \
487                 _x_.tx_size = _x_.tx_size_max;                  \
488             } else {                                            \
489                 int tmp  = _x_.tx_size - _x_.tx_size_max;       \
490                 tmp     %= _x_.tx_size_max - _x_.tx_size_min;   \
491                 _x_.tx_size = tmp + _x_.tx_size_min;            \
492             }                                                   \
493         }                                                       \
494     } while ( 0 )
495
496 // A similar macro for moving on to the next receive size. This is less
497 // critical since care is taken to always receive at least the current
498 // tx size plus padding.
499 // Note that padding needs to be added by the calling code, not here,
500 // since padding is only applicable on the host-side and this macro
501 // is used on both host and target.
502 #define USBTEST_NEXT_RX_SIZE(_x_)                               \
503     do {                                                        \
504         _x_.rx_size *= _x_.rx_size_multiplier;                  \
505         _x_.rx_size /= _x_.rx_size_divisor;                     \
506         _x_.rx_size += _x_.rx_size_increment;                   \
507         if (_x_.rx_size < _x_.rx_size_min) {                    \
508             if (_x_.rx_size_min == _x_.rx_size_max) {           \
509                 _x_.rx_size = _x_.rx_size_min;                  \
510             } else {                                            \
511                 int tmp  = _x_.rx_size_min - _x_.rx_size;       \
512                 tmp     %= _x_.rx_size_max - _x_.rx_size_min;   \
513                 _x_.rx_size = tmp + _x_.rx_size_min;            \
514             }                                                   \
515         } else if (_x_.rx_size > _x_.rx_size_max) {             \
516             if (_x_.rx_size_min == _x_.rx_size_max) {           \
517                 _x_.rx_size = _x_.rx_size_max;                  \
518             } else {                                            \
519                 int tmp  = _x_.rx_size - _x_.rx_size_max;       \
520                 tmp     %= _x_.rx_size_max - _x_.rx_size_min;   \
521                 _x_.rx_size = tmp + _x_.rx_size_min;            \
522             }                                                   \
523         }                                                       \
524     } while ( 0 )
525
526 // And a macro for adjusting the transmit delay.
527 #define USBTEST_NEXT_TX_DELAY(_x_)                              \
528     do {                                                        \
529         _x_.tx_delay *= _x_.tx_delay_multiplier;                \
530         _x_.tx_delay /= _x_.tx_delay_divisor;                   \
531         _x_.tx_delay += _x_.tx_delay_increment;                 \
532         if (_x_.tx_delay < _x_.tx_delay_min) {                  \
533             if (_x_.tx_delay_min == _x_.tx_delay_max) {         \
534                 _x_.tx_delay = _x_.tx_delay_min;                \
535             } else {                                            \
536                 int tmp  = _x_.tx_delay_min - _x_.tx_delay;     \
537                 tmp     %= _x_.tx_delay_max - _x_.tx_delay_min; \
538                 _x_.tx_delay = tmp + _x_.tx_delay_min;          \
539             }                                                   \
540         } else if (_x_.tx_delay > _x_.tx_delay_max) {           \
541             if (_x_.tx_delay_min == _x_.tx_delay_max) {         \
542                 _x_.tx_delay = _x_.tx_delay_max;                \
543             } else {                                            \
544                 int tmp  = _x_.tx_delay - _x_.tx_delay_max;     \
545                 tmp     %= _x_.tx_delay_max - _x_.tx_delay_min; \
546                 _x_.tx_delay = tmp + _x_.tx_delay_min;          \
547             }                                                   \
548         }                                                       \
549     } while ( 0 )
550
551 #define USBTEST_NEXT_RX_DELAY(_x_)                              \
552     do {                                                        \
553         _x_.rx_delay *= _x_.rx_delay_multiplier;                \
554         _x_.rx_delay /= _x_.rx_delay_divisor;                   \
555         _x_.rx_delay += _x_.rx_delay_increment;                 \
556         if (_x_.rx_delay < _x_.rx_delay_min) {                  \
557             if (_x_.rx_delay_min == _x_.rx_delay_max) {         \
558                 _x_.rx_delay = _x_.rx_delay_min;                \
559             } else {                                            \
560                 int tmp  = _x_.rx_delay_min - _x_.rx_delay;     \
561                 tmp     %= _x_.rx_delay_max - _x_.rx_delay_min; \
562                 _x_.rx_delay = tmp + _x_.rx_delay_min;          \
563             }                                                   \
564         } else if (_x_.rx_delay > _x_.rx_delay_max) {           \
565             if (_x_.rx_delay_min == _x_.rx_delay_max) {         \
566                 _x_.rx_delay = _x_.rx_delay_max;                \
567             } else {                                            \
568                 int tmp  = _x_.rx_delay - _x_.rx_delay_max;     \
569                 tmp     %= _x_.rx_delay_max - _x_.rx_delay_min; \
570                 _x_.rx_delay = tmp + _x_.rx_delay_min;          \
571             }                                                   \
572         }                                                       \
573     } while ( 0 )
574
575 #define USBTEST_BULK_NEXT(_bulk_)                               \
576     USBTEST_NEXT_TX_SIZE(_bulk_);                               \
577     USBTEST_NEXT_RX_SIZE(_bulk_);                               \
578     USBTEST_NEXT_TX_DELAY(_bulk_);                              \
579     USBTEST_NEXT_RX_DELAY(_bulk_);
580
581 // Control transfers, receives
582 typedef struct UsbTest_ControlIn {
583     int         number_packets;
584     int         packet_size_initial;
585     int         packet_size_min;
586     int         packet_size_max;
587     int         packet_size_multiplier;
588     int         packet_size_increment;
589     UsbTestData data;
590 } UsbTest_ControlIn;
591
592 #ifdef HOST
593 static void
594 pack_usbtest_control_in(UsbTest_ControlIn* test, unsigned char* buffer, int* index)
595 {
596     pack_int(test->number_packets,          buffer, index);
597     pack_int(test->packet_size_initial,     buffer, index);
598     pack_int(test->packet_size_min,         buffer, index);
599     pack_int(test->packet_size_max,         buffer, index);
600     pack_int(test->packet_size_multiplier,  buffer, index);
601     pack_int(test->packet_size_increment,   buffer, index);
602     pack_usbtestdata(&(test->data),         buffer, index);
603 }
604 #endif
605
606 #ifdef TARGET
607 static void
608 unpack_usbtest_control_in(UsbTest_ControlIn* test, unsigned char* buffer, int* index)
609 {
610     test->number_packets            = unpack_int(buffer, index);
611     test->packet_size_initial       = unpack_int(buffer, index);
612     test->packet_size_min           = unpack_int(buffer, index);
613     test->packet_size_max           = unpack_int(buffer, index);
614     test->packet_size_multiplier    = unpack_int(buffer, index);
615     test->packet_size_increment     = unpack_int(buffer, index);
616     unpack_usbtestdata(&(test->data), buffer, index);
617 }
618 #endif
619
620 // For now control packet sizes are adjusted in exactly the same way as bulk transfers.
621 #define USBTEST_CONTROL_NEXT_PACKET_SIZE(_packet_size_, _control_)                                          \
622     _packet_size_ = (_packet_size_ * _control_.packet_size_multiplier) + _control_.packet_size_increment;   \
623     if (_packet_size_ < _control_.packet_size_min) {                                                        \
624         _packet_size_ += _control_.packet_size_max - _control_.packet_size_min;                             \
625         if (_packet_size_ < _control_.packet_size_min) {                                                    \
626             _packet_size_ = _control_.packet_size_initial;                                                  \
627         }                                                                                                   \
628     } else if (_packet_size_ > _control_.packet_size_max) {                                                 \
629         _packet_size_ -= _control_.packet_size_max - _control_.packet_size_min;                             \
630         if (_packet_size_ > _control_.packet_size_max) {                                                    \
631             _packet_size_ = _control_.packet_size_initial;                                                  \
632         }                                                                                                   \
633     }
634
635 /*}}}*/
636 /*{{{  Recovery support                                         */
637
638 // ----------------------------------------------------------------------------
639 // When things go wrong threads on either the host or the target may get
640 // locked up waiting for further communication that never happens, because
641 // the other side has already raised an error. Recovery is possible by
642 // performing an extra I/O operation. For example, if a thread on the
643 // target is blocked waiting on an OUT endpoint then recovery is possible
644 // by the host sending some data to that endpoint. Similarly if a thread
645 // on the host is blocked then recovery involves the target either sending
646 // or receiving some additional data. There are alternative approaches such
647 // as stalling endpoints, but making sure that the requested communication
648 // actually happens involves fewer dependencies on exactly how those
649 // operations behave.
650
651 typedef struct UsbTest_Recovery {
652     int     endpoint;       // Top bit indicates direction, -1 indicates invalid
653     int     protocol;
654     int     size;
655 } UsbTest_Recovery;
656
657 static void
658 pack_usbtest_recovery(UsbTest_Recovery* recovery, unsigned char* buffer, int* index)
659 {
660     pack_int(recovery->endpoint, buffer, index);
661     pack_int(recovery->protocol, buffer, index);
662     pack_int(recovery->size,     buffer, index);
663 }
664
665 static void
666 unpack_usbtest_recovery(UsbTest_Recovery* recovery, unsigned char* buffer, int *index)
667 {
668     recovery->endpoint  = unpack_int(buffer, index);
669     recovery->protocol  = unpack_int(buffer, index);
670     recovery->size      = unpack_int(buffer, index);
671 }
672
673 static void
674 usbtest_recovery_reset(UsbTest_Recovery* recovery)
675 {
676     recovery->endpoint  = -1;
677     recovery->protocol  = 0;
678     recovery->size      = 0;
679 }
680
681 /*}}}*/