1 |
27 |
unneback |
/*{{{ 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 |
|
|
/*}}}*/
|