OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [usb/] [slave/] [v2_0/] [host/] [usbhost.c] - Blame information for rev 403

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
/*{{{  Banner                                                   */
2
 
3
//=================================================================
4
//
5
//        host.c
6
//
7
//        USB testing - host-side
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
// Author(s):     bartv
46
// Date:          2001-07-04
47
//####DESCRIPTIONEND####
48
//==========================================================================
49
 
50
// The overall architecture is as follows.
51
//
52
// The target hardware runs a special application which provides a
53
// particular type of USB application, "Red Hat eCos USB testing".
54
// This will not be recognised by any device driver, so the Linux
55
// kernel will pretty much ignore the device (other host OS's are not
56
// considered at this time).
57
//
58
// This program is the only supported way to interact with that service.
59
// It acts as an extended Tcl interpreter, providing a number of new
60
// Tcl commands for interacting with the target. All test cases can
61
// then be written as Tcl scripts which invoke a series of these commands.
62
// These Tcl commands operate essentially though the LINUX usb devfs
63
// service which allows ordinary application code to perform USB operations
64
// via ioctl()'s.
65
 
66
/*}}}*/
67
/*{{{  #include's                                               */
68
 
69
#include <stdio.h>
70
#include <stdlib.h>
71
#include <string.h>
72
#include <ctype.h>
73
#include <limits.h>
74
#include <errno.h>
75
#include <sys/types.h>
76
#include <sys/stat.h>
77
#include <unistd.h>
78
#include <fcntl.h>
79
#include <sys/ioctl.h>
80
#include <time.h>
81
#include <pthread.h>
82
#include <semaphore.h>
83
// Avoid compatibility problems with Tcl 8.4 vs. earlier
84
#define USE_NON_CONST
85
#include <tcl.h>
86
#include <linux/usb.h>
87
#include <linux/usbdevice_fs.h>
88
#include "../tests/protocol.h"
89
 
90
/*}}}*/
91
 
92
/*{{{  Statics                                                  */
93
 
94
// ----------------------------------------------------------------------------
95
// Statics.
96
 
97
// Has the current batch of tests actually terminated? This flag is
98
// checked by the various test handlers at appropriate intervals, and
99
// helps to handle the case where one of the side has terminated early
100
// because an error has been detected.
101
static int          current_tests_terminated = 0;
102
 
103
// The next local thread to be allocated for testing. This variable can also
104
// be used to find out how many threads are involved in the current test.
105
// This counter should always be reset to 0 at the end of every test run.
106
static int          local_thread_count      = 0;
107
 
108
// A similar counter for remote threads.
109
static int          remote_thread_count     = 0;
110
 
111
// A file handle for manipulating the USB device at a low level
112
static int          usb_master_fd  = -1;
113
 
114
/*}}}*/
115
/*{{{  Logging                                                  */
116
 
117
// ----------------------------------------------------------------------------
118
// The user can provide one or more -V/--verbose arguments to increase
119
// the amount of output generated.
120
 
121
static int verbose = 0;
122
 
123
#define VERBOSE(_level_, _format_, _args_...)   \
124
    do {                                        \
125
        if (verbose >= _level_) {               \
126
            printf(_format_, ## _args_);        \
127
        }                                       \
128
    } while (0);
129
 
130
/*}}}*/
131
/*{{{  Low-level USB access                                     */
132
 
133
// ----------------------------------------------------------------------------
134
// Low-level access to a USB device.
135
//
136
// The various ioctl() calls require a file handle which corresponds to one
137
// of the /proc/bus/usb/<abc>/<def> entries. <abc> is a bus number,
138
// typically 001 or 001, and <def> is a device number on that bus,
139
// e.g. 003. Figuring out <abc> and <def> requires scanning
140
// /proc/bus/usb/devices, which is a somewhat complicated text file.
141
//
142
// This is all somewhat vulnerable to incompatible changes in the
143
// Linux kernel, specifically the implementation of the /proc/bus/usb.
144
// An alternative approach would be to write a new Linux device driver
145
// and interact with that, but that approach is vulnerable to any
146
// internal kernel API changes affecting USB device drivers.
147
 
148
// How to access USB devices from userland
149
#define USB_ROOT        "/proc/bus/usb/"
150
 
151
// How to identify the eCos test case
152
#define PRODUCT_STRING    "Red Hat eCos USB test"
153
 
154
// Scan through /proc/bus/usb/devices looking for an entry that
155
// matches what we are after, specifically a line
156
//   S:  Product=Red Hat eCos USB testcase
157
// The required information can then be obtained from the previous
158
// line:
159
//   T:  Bus=<abc> ... Dev#= <def> ...
160
//
161
// Of course the T: line is going to come first, so it is necessary
162
// to keep track of the current bus and device numbers.
163
//
164
// Note: this code is duplicated in usbchmod.c. Any changes here
165
// should be propagated. For now the routine is too small to warrant
166
// a separate source file.
167
 
168
static int
169
usb_scan_devices(int* bus, int* dev)
170
{
171
    FILE*       devs_file;
172
    int         current_bus     = -1;
173
    int         current_dev     = -1;
174
    int         ch;
175
 
176
    *bus = -1;
177
    *dev = -1;
178
 
179
    VERBOSE(1, "Searching " USB_ROOT "devices for the eCos USB test code\n");
180
 
181
    devs_file = fopen(USB_ROOT "devices", "r");
182
    if (NULL == devs_file) {
183
        fprintf(stderr, "usbhost: error, unable to access " USB_ROOT "devices\n");
184
        return 0;
185
    }
186
    ch = getc(devs_file);
187
    while (EOF != ch) {
188
        if ('T' == ch) {
189
            if (2 !=fscanf(devs_file, ":  Bus=%d %*[^D\n]Dev#=%d", &current_bus, &current_dev)) {
190
                current_bus = -1;
191
                current_dev = -1;
192
            }
193
        } else if ('S' == ch) {
194
            int start = 0, end = 0;
195
            if (EOF != fscanf(devs_file, ":  Product=%n" PRODUCT_STRING "%n", &start, &end)) {
196
                if (start < end) {
197
                    *bus = current_bus;
198
                    *dev = current_dev;
199
                    break;
200
                }
201
            }
202
        }
203
        // Move to the end of the current line.
204
        do {
205
            ch = getc(devs_file);
206
        } while ((EOF != ch) && ('\n' != ch));
207
        if (EOF != ch) {
208
            ch = getc(devs_file);
209
        }
210
    }
211
 
212
    fclose(devs_file);
213
    if ((-1 != *bus) && (-1 != *dev)) {
214
        VERBOSE(1, "Found eCos USB test code on bus %d, device %d\n", *bus, *dev);
215
        return 1;
216
    }
217
    fprintf(stderr, "usbhost: error, failed to find a USB device \"" PRODUCT_STRING "\"\n");
218
    return 0;
219
}
220
 
221
// Actually open the USB device, allowing subsequent ioctl() operations.
222
//
223
// Typically /proc/bus/usb/... will not allow ordinary applications
224
// to perform ioctl()'s. Instead root privileges are required. To work
225
// around this there is a little utility usbchmod, installed suid,
226
// which can be used to get access to the raw device.
227
static int
228
usb_open_device(void)
229
{
230
    char devname[_POSIX_PATH_MAX];
231
    static int  bus = -1;
232
    static int  dev = -1;
233
    int         result;
234
 
235
    if ((-1 == bus) || (-1 == dev)) {
236
        if (!usb_scan_devices(&bus, &dev)) {
237
            return -1;
238
        }
239
    }
240
 
241
    if (_POSIX_PATH_MAX == snprintf(devname, _POSIX_PATH_MAX, USB_ROOT "%03d/%03d", bus, dev)) {
242
        fprintf(stderr, "usbhost: internal error, buffer overflow\n");
243
        exit(EXIT_FAILURE);
244
    }
245
 
246
    VERBOSE(1, "Attempting to access USB target via %s\n", devname);
247
 
248
    result = open(devname, O_RDWR);
249
    if (-1 == result) {
250
        // Check for access right problems. If so, try to work around them
251
        // by invoking usbchmod. Always look for this in the install tree,
252
        // since it is only that version which is likely to have been
253
        // chown'ed and chmod'ed to be suid root.
254
        if (EACCES == errno) {
255
            char command_name[_POSIX_PATH_MAX];
256
 
257
            VERBOSE(1, "Insufficient access to USB target, running usbchmod\n");
258
            if (_POSIX_PATH_MAX == snprintf(command_name, _POSIX_PATH_MAX, "%s/usbchmod %d %d", USBAUXDIR, bus, dev)) {
259
                fprintf(stderr, "usbhost: internal error, buffer overflow\n");
260
                exit(EXIT_FAILURE);
261
            }
262
            (void) system(command_name);
263
            result = open(devname, O_RDWR);
264
        }
265
    }
266
    if (-1 == result) {
267
        fprintf(stderr, "usbhost: error, failed to open \"%s\", errno %d\n", devname, errno);
268
    }
269
 
270
    VERBOSE(1, "USB device now accessible via file descriptor %d\n", result);
271
 
272
    // Also perform a set-configuration call, to avoid warnings from
273
    // the Linux kernel. Target-side testing is always configuration 1
274
    // because only a single configuration is supported.
275
    (void) ioctl(result, USBDEVFS_SETCONFIGURATION, 1);
276
    return result;
277
}
278
 
279
// Exchange a control message with the host. The return value should
280
// be 0, or a small positive number indicating the actual number of
281
// bytes received which may be less than requested.
282
//
283
// There appear to be problems with some hosts, manifesting itself as
284
// an inability to send control messages that involve additional data
285
// from host->target. These problems are not yet well-understood. For
286
// now the workaround is to send multiple packets, each with up to
287
// four bytes encoded in the index and length fields.
288
static int
289
usb_control_message(int fd, int request_type, int request, int value, int index, int length, void* data)
290
{
291
    struct usbdevfs_ctrltransfer        transfer;
292
    int         result = 0;
293
 
294
    VERBOSE(3, "usb_control_message, request %02x, len %d\n", request, length);
295
 
296
    if (length > USBTEST_MAX_CONTROL_DATA) {
297
        fprintf(stderr, "usbhost: internal error, control message involves too much data.\n");
298
        exit(EXIT_FAILURE);
299
    }
300
 
301
#if 1
302
    // Workaround - send additional data in the index and length fields.
303
    if ((length > 0) && (USB_DIR_OUT == (USB_ENDPOINT_DIR_MASK & request_type))) {
304
        int i;
305
        unsigned char*  buf = (unsigned char*) data;
306
 
307
        for (i = 0; i < length; i+= 4) {
308
            int this_len = length - 1;
309
            int ioctl_result;
310
 
311
            transfer.requesttype    = USB_TYPE_CLASS | USB_RECIP_DEVICE;
312
            if (this_len > 4) {
313
                this_len = 4;
314
            }
315
            switch (this_len) {
316
              case 1: transfer.request  = USBTEST_CONTROL_DATA1; break;
317
              case 2: transfer.request  = USBTEST_CONTROL_DATA2; break;
318
              case 3: transfer.request  = USBTEST_CONTROL_DATA3; break;
319
              case 4: transfer.request  = USBTEST_CONTROL_DATA4; break;
320
              default:
321
                fprintf(stderr, "usbhost: internal error, confusion about transfer length.\n");
322
                exit(EXIT_FAILURE);
323
            }
324
            transfer.value      = (buf[i]   << 8) | buf[i+1];   // Possible read beyond end of buffer,
325
            transfer.index      = (buf[i+2] << 8) | buf[i+3];   // but not worth worrying about.
326
            transfer.length     = 0;
327
            transfer.timeout    = 10 * 1000; // ten seconds, the target should always accept data faster than this.
328
            transfer.data       = NULL;
329
 
330
            // This is too strict, deciding what to do about errors should be
331
            // handled by higher-level code. However it will do for now.
332
            ioctl_result = ioctl(fd, USBDEVFS_CONTROL, &transfer);
333
            if (0 != ioctl_result) {
334
                fprintf(stderr, "usbhost: error, failed to send control message (data) to target.\n");
335
                exit(EXIT_FAILURE);
336
            }
337
        }
338
        // There is no more data to be transferred.
339
        length = 0;
340
    }
341
#endif    
342
    transfer.requesttype        = request_type;
343
    transfer.request            = request;
344
    transfer.value              = value;
345
    transfer.index              = index;
346
    transfer.length             = length;
347
    transfer.timeout            = 10000;
348
    transfer.data               = data;
349
 
350
    result = ioctl(fd, USBDEVFS_CONTROL, &transfer);
351
    return result;
352
}
353
 
354
// A variant of the above which can be called when the target should always respond
355
// correctly. This can be used for class control messages.
356
static int
357
usb_reliable_control_message(int fd, int request_type, int request, int value, int index, int length, void* data)
358
{
359
    int result = usb_control_message(fd, request_type, request, value, index, length, data);
360
    if (-1 == result) {
361
        fprintf(stderr, "usbhost: error, failed to send control message %02x to target.\n", request);
362
        fprintf(stderr, "       : errno %d (%s)\n", errno, strerror(errno));
363
        exit(EXIT_FAILURE);
364
    }
365
    return result;
366
}
367
 
368
 
369
// Either send or receive a single bulk message. The top bit of the endpoint
370
// number indicates the direction.
371
static int
372
usb_bulk_message(int fd, int endpoint, unsigned char* buffer, int length)
373
{
374
    struct  usbdevfs_bulktransfer    transfer;
375
    int     result;
376
 
377
    transfer.ep         = endpoint;
378
    transfer.len        = length;
379
    transfer.timeout    = 60 * 60 * 1000;
380
    // An hour. These operations should not time out because that
381
    // leaves the system in a confused state. Instead there is
382
    // higher-level recovery code that should ensure the operation
383
    // really does complete, and the return value here is used
384
    // by the calling code to determine whether the operation
385
    // was successful or whether there was an error and the recovery
386
    // code was invoked.
387
    transfer.data       = buffer;
388
    errno               = 0;
389
    result = ioctl(fd, USBDEVFS_BULK, &transfer);
390
    return result;
391
}
392
 
393
 
394
// Synchronise with the target. This can be used after the host has sent a request that
395
// may take a bit of time, e.g. it may involve waking up a thread. The host will send
396
// synch requests at regular intervals, until the target is ready.
397
//
398
// The limit argument can be used to avoid locking up. -1 means loop forever, otherwise
399
// it means that many iterations of 100ms apiece.
400
static int
401
usb_sync(int fd, int limit)
402
{
403
    unsigned char   buf[1];
404
    struct timespec delay;
405
    int             loops   = 0;
406
    int             result  = 0;
407
 
408
    VERBOSE(2, "Synchronizing with target\n");
409
 
410
    while (1) {
411
        buf[0]  = 0;
412
        usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_SYNCH, 0, 0, 1, buf);
413
        if (buf[0]) {
414
            result = 1;
415
            break;
416
        } else {
417
            if ((-1 != limit) && (++loops > limit)) {
418
                break;
419
            } else {
420
                VERBOSE(3, "Not yet synchronized, sleeping\n");
421
                delay.tv_sec    = 0;
422
                delay.tv_nsec   = 100000000;    // 100 ms
423
                nanosleep(&delay, NULL);
424
            }
425
        }
426
    }
427
    VERBOSE(2, "%s\n", result ? "Synchronized" : "Not synchronized");
428
    return result;
429
}
430
 
431
// Abort the target. Things seem to be completely messed up and there is no easy
432
// way to restore sanity to both target and host.
433
static void
434
usb_abort(int fd)
435
{
436
    VERBOSE(2, "Target-side abort operation invoked\n");
437
    usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_ABORT, 0, 0, 0, (void*)0);
438
}
439
 
440
/*}}}*/
441
/*{{{  Initialise endpoints                                     */
442
 
443
// ----------------------------------------------------------------------------
444
// On power-up some endpoints may not be in a sensible state. For example,
445
// with the SA11x0 the hardware may start accepting bulk OUT transfers
446
// before the target-side software has started a receive operation,
447
// so if the host sends a bulk packet before the target is ready then
448
// things get messy. This is especially troublesome if the target-side
449
// attempts any diagnostic output because of verbosity.
450
//
451
// This code loops through the various endpoints and makes sure that
452
// they are all in a reasonable state, before any real tests get run
453
// That means known hardware flaws do not show up as test failures,
454
// but of course they are still documented and application software
455
// will have to do the right thing.
456
 
457
static void
458
usb_initialise_control_endpoint(int min_size, int max_size)
459
{
460
    // At this time there are no known problems on any hardware
461
    // that would need to be addressed
462
}
463
 
464
static void
465
usb_initialise_isochronous_in_endpoint(int number, int min_size, int max_size)
466
{
467
    // At this time there are no known problems on any hardware
468
    // that would need to be addressed
469
}
470
 
471
static void
472
usb_initialise_isochronous_out_endpoint(int number, int min_size, int max_size)
473
{
474
    // At this time there are no known problems on any hardware
475
    // that would need to be addressed
476
}
477
 
478
static void
479
usb_initialise_bulk_in_endpoint(int number, int min_size, int max_size, int padding)
480
{
481
    // At this time there are no known problems on any hardware
482
    // that would need to be addressed
483
}
484
 
485
static void
486
usb_initialise_bulk_out_endpoint(int number, int min_size, int max_size)
487
{
488
    char buf[1];
489
 
490
    // On the SA1110 the hardware comes up with a bogus default value,
491
    // causing the hardware to accept packets before the software has
492
    // set up DMA or in any way prepared for incoming data. This is
493
    // a problem. It is worked around by making the target receive
494
    // a single packet, sending that packet, and then performing a
495
    // sync.
496
    VERBOSE(2, "Performing bulk OUT initialization on endpoint %d\n", number);
497
 
498
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
499
                                 USBTEST_INIT_BULK_OUT, number, 0, 0, (void*) 0);
500
    usb_bulk_message(usb_master_fd, number, buf, 1);
501
    usb_sync(usb_master_fd, 10);
502
}
503
 
504
static void
505
usb_initialise_interrupt_in_endpoint(int number, int min_size, int max_size)
506
{
507
    // At this time there are no known problems on any hardware
508
    // that would need to be addressed
509
}
510
 
511
static void
512
usb_initialise_interrupt_out_endpoint(int number, int min_size, int max_size)
513
{
514
    // At this time there are no known problems on any hardware
515
    // that would need to be addressed
516
}
517
 
518
/*}}}*/
519
/*{{{  Host/target common code                                  */
520
 
521
#define HOST
522
#include "../tests/common.c"
523
 
524
/*}}}*/
525
/*{{{  The test cases themselves                                */
526
 
527
/*{{{  UsbTest definition                                       */
528
 
529
// ----------------------------------------------------------------------------
530
// All the data associated with a single test.
531
 
532
typedef struct UsbTest {
533
 
534
    // A "unique" identifier to make verbose output easier to understand.
535
    int                 id;
536
    // Which file descriptor should be used to access USB.
537
    int                 fd;
538
 
539
    // Which test should be run.
540
    usbtest             which_test;
541
 
542
    // Test-specific details.
543
    union {
544
        UsbTest_Bulk        bulk;
545
        UsbTest_ControlIn   control_in;
546
    } test_params;
547
 
548
    // How to recover from any problems. Specifically, what kind of message
549
    // could the target send or receive that would unlock the thread on this
550
    // side.
551
    UsbTest_Recovery    recovery;
552
 
553
    int                 result_pass;
554
    char                result_message[USBTEST_MAX_MESSAGE];
555
    unsigned char       buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];
556
} UsbTest;
557
 
558
// Reset the information in a given test. This is used by the pool allocation
559
// code. The data union is left alone, filling in the appropriate union
560
// member is left to other code.
561
static void
562
reset_usbtest(UsbTest* test)
563
{
564
    static int next_id = 1;
565
    test->id                    = next_id++;
566
    test->which_test            = usbtest_invalid;
567
    usbtest_recovery_reset(&(test->recovery));
568
    test->result_pass           = 0;
569
    test->result_message[0]     = '\0';
570
}
571
 
572
/*}}}*/
573
/*{{{  bulk OUT                                                 */
574
 
575
static void
576
run_test_bulk_out(UsbTest* test)
577
{
578
    unsigned char*  buf     = test->buffer;
579
    int             i;
580
 
581
    VERBOSE(1, "Starting test %d, bulk OUT on endpoint %d\n", test->id, test->test_params.bulk.endpoint);
582
 
583
    for (i = 0; i < test->test_params.bulk.number_packets; i++) {
584
        int transferred;
585
        int packet_size = test->test_params.bulk.tx_size;
586
 
587
        test->recovery.endpoint     = test->test_params.bulk.endpoint;
588
        test->recovery.protocol     = USB_ENDPOINT_XFER_BULK;
589
        test->recovery.size         = packet_size;
590
 
591
        usbtest_fill_buffer(&(test->test_params.bulk.data), buf, packet_size);
592
        if (verbose < 3) {
593
            VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size %d\n", test->id, i, packet_size);
594
        } else {
595
            // Output the first 32 bytes of data as well.
596
            char msg[256];
597
            int  index;
598
            int  j;
599
            index = snprintf(msg, 255, "Bulk OUT test %d: iteration %d, packet size %d\n    Data %s:",
600
                             test->id, i, packet_size,
601
                             (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : "");
602
 
603
            for (j = 0; ((j + 3) < packet_size) && (j < 32); j+= 4) {
604
                index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x",
605
                                  buf[j], buf[j+1], buf[j+2], buf[j+3]);
606
            }
607
            if (j < 32) {
608
                index += snprintf(msg+index, 255-index, " ");
609
                for ( ; j < packet_size; j++) {
610
                    index += snprintf(msg+index, 255-index, "%02x", buf[j]);
611
                }
612
 
613
            }
614
            VERBOSE(3, "%s\n", msg);
615
        }
616
 
617
        transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, packet_size);
618
 
619
        // Has this test run been aborted for some reason?
620
        if (current_tests_terminated) {
621
            VERBOSE(2, "Bulk OUT test %d: iteration %d, termination detected\n", test->id, i);
622
            test->result_pass = 0;
623
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
624
                     "Host, bulk OUT transfer on endpoint %d: aborted after %d iterations\n",
625
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i);
626
            return;
627
        }
628
 
629
        // If an error occurred, abort this run.
630
        if (-1 == transferred) {
631
            char    errno_buf[USBTEST_MAX_MESSAGE];
632
            test->result_pass  = 0;
633
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
634
                     "Host, bulk OUT transfer on endpoint %d : host ioctl() system call failed\n    errno %d (%s)",
635
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno,
636
                     strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
637
            VERBOSE(2, "Bulk OUT test %d: iteration %d, error:\n    %s\n", test->id, i, test->result_message);
638
            break;
639
        }
640
 
641
        if (0 != test->test_params.bulk.tx_delay) {
642
            struct timespec delay;
643
 
644
            VERBOSE(2, "Bulk OUT test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \
645
                    i, test->test_params.bulk.tx_delay);
646
            // Note that nanosleep() can return early due to incoming signals,
647
            // with the unelapsed time returned in a second argument. This
648
            // allows for a retry loop. In practice this does not seem
649
            // worthwhile, the delays are approximate anyway.
650
            delay.tv_sec  = test->test_params.bulk.tx_delay / 1000000000;
651
            delay.tv_nsec = test->test_params.bulk.tx_delay % 1000000000;
652
            nanosleep(&delay, NULL);
653
        }
654
 
655
        // Now move on to the next transfer
656
        USBTEST_BULK_NEXT(test->test_params.bulk);
657
    }
658
 
659
    // If all the packets have been transferred this test has passed.
660
    if (i >= test->test_params.bulk.number_packets) {
661
        test->result_pass   = 1;
662
    }
663
 
664
    VERBOSE(1, "Test %d bulk OUT on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass);
665
}
666
 
667
/*}}}*/
668
/*{{{  bulk IN                                                  */
669
 
670
static void
671
run_test_bulk_in(UsbTest* test)
672
{
673
    unsigned char*  buf     = test->buffer;
674
    int             i;
675
 
676
    VERBOSE(1, "Starting test %d bulk IN on endpoint %d\n", test->id, test->test_params.bulk.endpoint);
677
 
678
    for (i = 0; i < test->test_params.bulk.number_packets; i++) {
679
        int transferred;
680
        int tx_size             = test->test_params.bulk.tx_size;
681
        int rx_size             = test->test_params.bulk.rx_size;
682
        int size_plus_padding;
683
 
684
        VERBOSE(2, "Bulk IN test %d: iteration %d, rx size %d, tx size %d\n", test->id, i, rx_size, tx_size);
685
 
686
        if (rx_size < tx_size) {
687
            rx_size = tx_size;
688
            VERBOSE(2, "Bulk IN test %d: iteration %d, packet size reset to %d to match tx size\n",
689
                    test->id, i, rx_size);
690
        }
691
        test->recovery.endpoint     = test->test_params.bulk.endpoint;
692
        test->recovery.protocol     = USB_ENDPOINT_XFER_BULK;
693
        test->recovery.size         = rx_size;
694
 
695
        // Make sure there is no old data lying around
696
        if (usbtestdata_none != test->test_params.bulk.data.format) {
697
            memset(buf, 0, rx_size);
698
        }
699
 
700
        // And do the actual transfer.
701
        size_plus_padding = rx_size;
702
        if (size_plus_padding < (tx_size + test->test_params.bulk.rx_padding)) {
703
            size_plus_padding += test->test_params.bulk.rx_padding;
704
        }
705
        do {
706
            transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, size_plus_padding);
707
        } while (0 == transferred);
708
 
709
        // Has this test run been aborted for some reason?
710
        if (current_tests_terminated) {
711
            VERBOSE(2, "Bulk IN test %d: iteration %d, termination detected\n", test->id, i);
712
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
713
                     "Host, bulk IN transfer on endpoint %d: aborted after %d iterations\n",
714
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i);
715
            return;
716
        }
717
 
718
        // If an error occurred, abort this run.
719
        if (-1 == transferred) {
720
            char    errno_buf[USBTEST_MAX_MESSAGE];
721
            test->result_pass  = 0;
722
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
723
                     "Host, bulk IN transfer on endpoint %d : host ioctl() system call failed\n    errno %d (%s)",
724
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno,
725
                     strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
726
            VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n    %s\n", test->id, i, test->result_message);
727
            break;
728
        }
729
 
730
        // Did the target send the expected amount of data?
731
        if (transferred < tx_size) {
732
            test->result_pass   = 0;
733
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
734
                     "Host, bulk IN transfer on endpoint %d : the target only sent %d bytes when %d were expected",
735
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, transferred, tx_size);
736
            VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n    %s\n", test->id, i, test->result_message);
737
            break;
738
        }
739
 
740
        if (verbose >= 3) {
741
            // Output the first 32 bytes of data
742
            char msg[256];
743
            int  index;
744
            int  j;
745
            index = snprintf(msg, 255, "Bulk IN test %d: iteration %d, transferred %d\n    Data %s:",
746
                             test->id, i, transferred,
747
                             (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : "");
748
 
749
            for (j = 0; ((j + 3) < transferred) && (j < 32); j+= 4) {
750
                index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x",
751
                                  buf[j], buf[j+1], buf[j+2], buf[j+3]);
752
            }
753
            if (j < 32) {
754
                index += snprintf(msg+index, 255-index, " ");
755
                for ( ; j < transferred; j++) {
756
                    index += snprintf(msg+index, 255-index, "%02x", buf[j]);
757
                }
758
 
759
            }
760
            VERBOSE(3, "%s\n", msg);
761
        }
762
 
763
        // Is the data correct?
764
        if (!usbtest_check_buffer(&(test->test_params.bulk.data), buf, tx_size)) {
765
            test->result_pass   = 0;
766
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
767
                     "Host, bulk IN transfer on endpoint %d : mismatch between received and expected data",
768
                     test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK);
769
            VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n    %s\n", test->id, i, test->result_message);
770
            break;
771
        }
772
 
773
        if (0 != test->test_params.bulk.rx_delay) {
774
            struct timespec delay;
775
 
776
            VERBOSE(2, "Bulk IN test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \
777
                    i, test->test_params.bulk.tx_delay);
778
            // Note that nanosleep() can return early due to incoming signals,
779
            // with the unelapsed time returned in a second argument. This
780
            // allows for a retry loop. In practice this does not seem
781
            // worthwhile, the delays are approximate anyway.
782
            delay.tv_sec  = test->test_params.bulk.rx_delay / 1000000000;
783
            delay.tv_nsec = test->test_params.bulk.rx_delay % 1000000000;
784
            nanosleep(&delay, NULL);
785
        }
786
 
787
        USBTEST_BULK_NEXT(test->test_params.bulk);
788
    }
789
 
790
 
791
    // If all the packets have been transferred this test has passed.
792
    if (i >= test->test_params.bulk.number_packets) {
793
        test->result_pass   = 1;
794
    }
795
 
796
    VERBOSE(1, "Test %d bulk IN on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass);
797
}
798
 
799
/*}}}*/
800
/*{{{  control IN                                               */
801
 
802
// Receive appropriate packets via the control endpoint. This is somewhat
803
// different from bulk transfers. It is implemented using reserved control
804
// messages.
805
//
806
// Note: it is not entirely clear that this test is safe. There will be
807
// concurrent control traffic to detect test termination and the like,
808
// and these control messages may interfere with each other. It is not
809
// entirely clear how the Linux kernel handles concurrent control
810
// operations.
811
 
812
static void
813
run_test_control_in(UsbTest* test)
814
{
815
    unsigned char*  buf     = test->buffer;
816
    int             packet_size;
817
    int             i;
818
 
819
    packet_size = test->test_params.control_in.packet_size_initial;
820
    for (i = 0; i < test->test_params.control_in.number_packets; i++) {
821
        int transferred;
822
 
823
        test->recovery.endpoint     = 0;
824
        test->recovery.protocol     = USB_ENDPOINT_XFER_CONTROL;
825
        test->recovery.size         = packet_size;
826
 
827
        // Make sure there is no old data lying around
828
        if (usbtestdata_none != test->test_params.control_in.data.format) {
829
            memset(buf, 0, packet_size);
830
        }
831
 
832
        // And do the actual transfer.
833
        transferred = usb_control_message(test->fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_RESERVED_CONTROL_IN,
834
                                          0, 0, packet_size, buf);
835
 
836
        // Has this test run been aborted for some reason?
837
        if (current_tests_terminated) {
838
            return;
839
        }
840
 
841
        // If an error occurred, abort this run.
842
        if (-1 == transferred) {
843
            char    errno_buf[USBTEST_MAX_MESSAGE];
844
            test->result_pass  = 0;
845
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
846
                     "Host, control IN transfer: host ioctl() system call failed\n    errno %d (%s)",
847
                     errno, strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
848
            break;
849
        }
850
 
851
        // Did the target send the expected amount of data?
852
        if (transferred < packet_size) {
853
            test->result_pass   = 0;
854
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
855
                     "Host, control IN transfer: the target only sent %d bytes when %d were expected",
856
                     transferred, packet_size);
857
            break;
858
        }
859
 
860
        // Is the data correct?
861
        if (!usbtest_check_buffer(&(test->test_params.control_in.data), buf, packet_size)) {
862
            test->result_pass   = 0;
863
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
864
                     "Host, control IN transfer: mismatch between received and expected data");
865
            break;
866
        }
867
 
868
        USBTEST_CONTROL_NEXT_PACKET_SIZE(packet_size, test->test_params.control_in);
869
    }
870
 
871
    // If all the packets have been transferred this test has passed.
872
    if (i >= test->test_params.control_in.number_packets) {
873
        test->result_pass   = 1;
874
    }
875
}
876
 
877
/*}}}*/
878
 
879
// FIXME: add more tests
880
 
881
/*{{{  run_test()                                               */
882
 
883
// This utility is invoked from a thread in the thread pool whenever there is
884
// work to be done. It simply dispatches to the appropriate handler.
885
static void
886
run_test(UsbTest* test)
887
{
888
    switch (test->which_test) {
889
      case usbtest_bulk_out:    run_test_bulk_out(test); break;
890
      case usbtest_bulk_in:     run_test_bulk_in(test); break;
891
      case usbtest_control_in:  run_test_control_in(test); break;
892
      default:
893
        fprintf(stderr, "usbhost: internal error, attempt to execute an unknown test.\n");
894
        exit(EXIT_FAILURE);
895
    }
896
}
897
 
898
/*}}}*/
899
 
900
/*}}}*/
901
/*{{{  The thread pool                                          */
902
 
903
// ----------------------------------------------------------------------------
904
// A pool of threads and buffers which do the real work. The number of possible
905
// concurrent tests is defined in protocol.h. Each one requires a separate
906
// thread, transfer buffer, semaphore, and some state information.
907
//
908
// Although the application is multi-threaded, in practice there is little
909
// need for synchronization. Tests will only be started while the pool threads
910
// are idle. When the pool threads are running the main thread will be waiting
911
// for them all to finish, with a bit of polling to detect error conditions.
912
// The pool threads do not share any data, apart from the file descriptor for
913
// the USB device.
914
 
915
typedef struct PoolEntry {
916
    pthread_t       thread;
917
    sem_t           wakeup;
918
    int             running;
919
    UsbTest         test;
920
} PoolEntry;
921
 
922
static PoolEntry pool[USBTEST_MAX_CONCURRENT_TESTS];
923
 
924
// This is the entry point for every thread in the pool. It just loops forever,
925
// waiting until it is supposed to run a test. These threads never actually
926
// exit, instead there should be a call to exit() somewhere.
927
static void*
928
pool_function(void* arg)
929
{
930
    PoolEntry*  pool_entry  = (PoolEntry*) arg;
931
    for ( ; ; ) {
932
        sem_wait(&(pool_entry->wakeup));
933
        run_test(&(pool_entry->test));
934
        pool_entry->running = 0;
935
    }
936
 
937
    return NULL;
938
}
939
 
940
// Initialize all threads in the pool.
941
static void
942
pool_initialize(void)
943
{
944
    int i;
945
    for (i = 0; i < USBTEST_MAX_CONCURRENT_TESTS; i++) {
946
        pool[i].running = 0;
947
        pool[i].test.fd = dup(usb_master_fd);
948
        if (0 != sem_init(&(pool[i].wakeup), 0, 0)) {
949
            fprintf(stderr, "usbhost: internal error, failed to initialize all semaphores.\n");
950
            exit(EXIT_FAILURE);
951
        }
952
        if (0 != pthread_create(&(pool[i].thread), NULL, &pool_function, (void*) &(pool[i]))) {
953
            fprintf(stderr, "usbhost: internal error, failed to start all threads.\n");
954
            exit(EXIT_FAILURE);
955
        }
956
    }
957
}
958
 
959
// Allocate a single entry in the thread pool.
960
static UsbTest*
961
pool_allocate(void)
962
{
963
    UsbTest* result = (UsbTest*) 0;
964
 
965
    if (local_thread_count == USBTEST_MAX_CONCURRENT_TESTS) {
966
        fprintf(stderr, "usbhost: internal error, thread resource exhausted.\n");
967
        exit(EXIT_FAILURE);
968
    }
969
 
970
    result = &(pool[local_thread_count].test);
971
    local_thread_count++;
972
    reset_usbtest(result);
973
    return result;
974
}
975
 
976
// Start all the threads that are supposed to be running tests.
977
static void
978
pool_start(void)
979
{
980
    int i;
981
    for (i = 0; i < local_thread_count; i++) {
982
        pool[i].running = 1;
983
        sem_post(&(pool[i].wakeup));
984
    }
985
}
986
 
987
/*}}}*/
988
/*{{{  Tcl routines                                             */
989
 
990
// ----------------------------------------------------------------------------
991
// Tcl routines to provide access to the USB device from inside Tcl
992
// scripts, plus some general utilities. These routines deal mostly
993
// with preparing a test run. The actual work is done in C: the
994
// ioctl() operations are not readily accessible from Tcl, and
995
// operations like filling in buffers and calculating checksums are
996
// cpu-intensive.
997
 
998
/*{{{  pass/fail/abort                                          */
999
 
1000
// ----------------------------------------------------------------------------
1001
// Some simple routines accessible from Tcl to get the target to report pass/fail or
1002
// to make the target abort.
1003
 
1004
static int
1005
tcl_target_pass(ClientData     clientData  __attribute__ ((unused)),
1006
                Tcl_Interp*    interp,
1007
                int            argc,
1008
                char**         argv)
1009
{
1010
    if (2 != argc) {
1011
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass <message>\"", TCL_STATIC);
1012
        return TCL_ERROR;
1013
    }
1014
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS, 0, 0, strlen(argv[1]) + 1, argv[1]);
1015
    usb_sync(usb_master_fd, -1);
1016
    return TCL_OK;
1017
}
1018
 
1019
static int
1020
tcl_target_fail(ClientData     clientData  __attribute__ ((unused)),
1021
                Tcl_Interp*    interp,
1022
                int            argc,
1023
                char**         argv)
1024
{
1025
    if (2 != argc) {
1026
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail <message>\"", TCL_STATIC);
1027
        return TCL_ERROR;
1028
    }
1029
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL, 0, 0, strlen(argv[1]) + 1, argv[1]);
1030
    usb_sync(usb_master_fd, -1);
1031
    return TCL_OK;
1032
}
1033
 
1034
// The next three routines cause the target to exit, so a usb_sync() is inappropriate.
1035
static int
1036
tcl_target_pass_exit(ClientData     clientData  __attribute__ ((unused)),
1037
                     Tcl_Interp*    interp,
1038
                     int            argc,
1039
                     char**         argv)
1040
{
1041
    if (2 != argc) {
1042
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass_exit <message>\"", TCL_STATIC);
1043
        return TCL_ERROR;
1044
    }
1045
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS_EXIT, 0, 0,
1046
                                 strlen(argv[1]) + 1, argv[1]);
1047
    return TCL_OK;
1048
}
1049
 
1050
 
1051
static int
1052
tcl_target_fail_exit(ClientData     clientData  __attribute__ ((unused)),
1053
                     Tcl_Interp*    interp,
1054
                     int            argc,
1055
                     char**         argv)
1056
{
1057
    if (2 != argc) {
1058
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail_exit <message>\"", TCL_STATIC);
1059
        return TCL_ERROR;
1060
    }
1061
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL_EXIT, 0, 0,
1062
                                 strlen(argv[1]) + 1, argv[1]);
1063
    return TCL_OK;
1064
}
1065
 
1066
static int
1067
tcl_target_abort(ClientData     clientData  __attribute__ ((unused)),
1068
                 Tcl_Interp*    interp,
1069
                 int            argc,
1070
                 char**         argv        __attribute__ ((unused)) )
1071
{
1072
    if (1 != argc) {
1073
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_abort\"", TCL_STATIC);
1074
        return TCL_ERROR;
1075
    }
1076
    usb_abort(usb_master_fd);
1077
    return TCL_OK;
1078
}
1079
 
1080
/*}}}*/
1081
/*{{{  start bulk test                                          */
1082
 
1083
// ----------------------------------------------------------------------------
1084
// Start a bulk test. The real Tcl interface to this functionality is
1085
// implemented in Tcl: it takes care of figuring out sensible default
1086
// arguments, validating the data, etc. All that this code does is
1087
// allocate a thread and fill in the appropriate data, plus request
1088
// the target-side to do the same thing.
1089
 
1090
static int
1091
tcl_test_bulk(ClientData     clientData  __attribute__ ((unused)),
1092
              Tcl_Interp*    interp,
1093
              int            argc,
1094
              char**         argv)
1095
{
1096
    int             i;
1097
    int             tmp;
1098
    UsbTest*        test;
1099
    unsigned char   request[USBTEST_MAX_CONTROL_DATA];
1100
    int             request_index;
1101
 
1102
    // The data consists of 28 numbers for UsbTest_Bulk itself, and
1103
    // another 10 numbers for the test data definition.
1104
    if (39 != argc) {
1105
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_test_bulk <message>\"", TCL_STATIC);
1106
        return TCL_ERROR;
1107
    }
1108
    for (i = 1; i < 39; i++) {
1109
        int discard;
1110
        if (TCL_OK != Tcl_GetInt(interp, argv[i], &discard)) {
1111
            Tcl_SetResult(interp, "invalid argument: all arguments should be numbers", TCL_STATIC);
1112
            return TCL_ERROR;
1113
        }
1114
    }
1115
 
1116
    test = pool_allocate();
1117
    Tcl_GetInt(interp, argv[1], &(test->test_params.bulk.number_packets));
1118
    Tcl_GetInt(interp, argv[2], &(test->test_params.bulk.endpoint));
1119
    test->which_test = (USB_DIR_IN == (test->test_params.bulk.endpoint & USB_ENDPOINT_DIR_MASK))
1120
        ? usbtest_bulk_in : usbtest_bulk_out;
1121
    Tcl_GetInt(interp, argv[ 3], &(test->test_params.bulk.tx_size));
1122
    Tcl_GetInt(interp, argv[ 4], &(test->test_params.bulk.tx_size_min));
1123
    Tcl_GetInt(interp, argv[ 5], &(test->test_params.bulk.tx_size_max));
1124
    Tcl_GetInt(interp, argv[ 6], &(test->test_params.bulk.tx_size_multiplier));
1125
    Tcl_GetInt(interp, argv[ 7], &(test->test_params.bulk.tx_size_divisor));
1126
    Tcl_GetInt(interp, argv[ 8], &(test->test_params.bulk.tx_size_increment));
1127
    Tcl_GetInt(interp, argv[ 9], &(test->test_params.bulk.rx_size));
1128
    Tcl_GetInt(interp, argv[10], &(test->test_params.bulk.rx_size_min));
1129
    Tcl_GetInt(interp, argv[11], &(test->test_params.bulk.rx_size_max));
1130
    Tcl_GetInt(interp, argv[12], &(test->test_params.bulk.rx_size_multiplier));
1131
    Tcl_GetInt(interp, argv[13], &(test->test_params.bulk.rx_size_divisor));
1132
    Tcl_GetInt(interp, argv[14], &(test->test_params.bulk.rx_size_increment));
1133
    Tcl_GetInt(interp, argv[15], &(test->test_params.bulk.rx_padding));
1134
    Tcl_GetInt(interp, argv[16], &(test->test_params.bulk.tx_delay));
1135
    Tcl_GetInt(interp, argv[17], &(test->test_params.bulk.tx_delay_min));
1136
    Tcl_GetInt(interp, argv[18], &(test->test_params.bulk.tx_delay_max));
1137
    Tcl_GetInt(interp, argv[19], &(test->test_params.bulk.tx_delay_multiplier));
1138
    Tcl_GetInt(interp, argv[20], &(test->test_params.bulk.tx_delay_divisor));
1139
    Tcl_GetInt(interp, argv[21], &(test->test_params.bulk.tx_delay_increment));
1140
    Tcl_GetInt(interp, argv[22], &(test->test_params.bulk.rx_delay));
1141
    Tcl_GetInt(interp, argv[23], &(test->test_params.bulk.rx_delay_min));
1142
    Tcl_GetInt(interp, argv[24], &(test->test_params.bulk.rx_delay_max));
1143
    Tcl_GetInt(interp, argv[25], &(test->test_params.bulk.rx_delay_multiplier));
1144
    Tcl_GetInt(interp, argv[26], &(test->test_params.bulk.rx_delay_divisor));
1145
    Tcl_GetInt(interp, argv[27], &(test->test_params.bulk.rx_delay_increment));
1146
    Tcl_GetInt(interp, argv[28], &tmp);
1147
    test->test_params.bulk.io_mechanism = (usb_io_mechanism) tmp;
1148
    Tcl_GetInt(interp, argv[29], &tmp);
1149
    test->test_params.bulk.data.format = (usbtestdata) tmp;
1150
    Tcl_GetInt(interp, argv[30], &(test->test_params.bulk.data.seed));
1151
    Tcl_GetInt(interp, argv[31], &(test->test_params.bulk.data.multiplier));
1152
    Tcl_GetInt(interp, argv[32], &(test->test_params.bulk.data.increment));
1153
    Tcl_GetInt(interp, argv[33], &(test->test_params.bulk.data.transfer_seed_multiplier));
1154
    Tcl_GetInt(interp, argv[34], &(test->test_params.bulk.data.transfer_seed_increment));
1155
    Tcl_GetInt(interp, argv[35], &(test->test_params.bulk.data.transfer_multiplier_multiplier));
1156
    Tcl_GetInt(interp, argv[36], &(test->test_params.bulk.data.transfer_multiplier_increment));
1157
    Tcl_GetInt(interp, argv[37], &(test->test_params.bulk.data.transfer_increment_multiplier));
1158
    Tcl_GetInt(interp, argv[38], &(test->test_params.bulk.data.transfer_increment_increment));
1159
 
1160
    VERBOSE(3, "Preparing USB bulk test on endpoint %d, direction %s, for %d packets\n", \
1161
            test->test_params.bulk.endpoint, \
1162
            (usbtest_bulk_in == test->which_test) ? "IN" : "OUT", \
1163
            test->test_params.bulk.number_packets);
1164
    VERBOSE(3, "  I/O mechanism is %s\n", \
1165
            (usb_io_mechanism_usb == test->test_params.bulk.io_mechanism) ? "low-level USB" : \
1166
            (usb_io_mechanism_dev == test->test_params.bulk.io_mechanism) ? "devtab" : "<invalid>");
1167
    VERBOSE(3, "  Data format %s, data1 %d, data* %d, data+ %d, data1* %d, data1+ %d, data** %d, data*+ %d, data+* %d, data++ %d\n",\
1168
            (usbtestdata_none     == test->test_params.bulk.data.format) ? "none" :     \
1169
            (usbtestdata_bytefill == test->test_params.bulk.data.format) ? "bytefill" : \
1170
            (usbtestdata_wordfill == test->test_params.bulk.data.format) ? "wordfill" : \
1171
            (usbtestdata_byteseq  == test->test_params.bulk.data.format) ? "byteseq"  : \
1172
            (usbtestdata_wordseq  == test->test_params.bulk.data.format) ? "wordseq"  : "<invalid>", \
1173
            test->test_params.bulk.data.seed,                            \
1174
            test->test_params.bulk.data.multiplier,                      \
1175
            test->test_params.bulk.data.increment,                       \
1176
            test->test_params.bulk.data.transfer_seed_multiplier,        \
1177
            test->test_params.bulk.data.transfer_seed_increment,         \
1178
            test->test_params.bulk.data.transfer_multiplier_multiplier,  \
1179
            test->test_params.bulk.data.transfer_multiplier_increment,   \
1180
            test->test_params.bulk.data.transfer_increment_multiplier,   \
1181
            test->test_params.bulk.data.transfer_increment_increment);
1182
    VERBOSE(3, "  txsize1 %d, txsize>= %d, txsize<= %d, txsize* %d, txsize/ %d, txsize+ %d\n", \
1183
            test->test_params.bulk.tx_size,         test->test_params.bulk.tx_size_min,        \
1184
            test->test_params.bulk.tx_size_max,     test->test_params.bulk.tx_size_multiplier, \
1185
            test->test_params.bulk.tx_size_divisor, test->test_params.bulk.tx_size_increment);
1186
    VERBOSE(3, "  rxsize1 %d, rxsize>= %d, rxsize<= %d, rxsize* %d, rxsize/ %d, rxsize+ %d\n", \
1187
            test->test_params.bulk.rx_size,         test->test_params.bulk.rx_size_min,        \
1188
            test->test_params.bulk.rx_size_max,     test->test_params.bulk.rx_size_multiplier, \
1189
            test->test_params.bulk.rx_size_divisor, test->test_params.bulk.rx_size_increment);
1190
    VERBOSE(3, "  txdelay1 %d, txdelay>= %d, txdelay<= %d, txdelay* %d, txdelay/ %d, txdelay+ %d\n", \
1191
            test->test_params.bulk.tx_delay,         test->test_params.bulk.tx_delay_min,            \
1192
            test->test_params.bulk.tx_delay_max,     test->test_params.bulk.tx_delay_multiplier,     \
1193
            test->test_params.bulk.tx_delay_divisor, test->test_params.bulk.tx_delay_increment);
1194
    VERBOSE(3, "  rxdelay1 %d, rxdelay>= %d, rxdelay<= %d, rxdelay* %d, rxdelay/ %d, rxdelay+ %d\n", \
1195
            test->test_params.bulk.rx_delay,         test->test_params.bulk.rx_delay_min,            \
1196
            test->test_params.bulk.rx_delay_max,     test->test_params.bulk.rx_delay_multiplier,     \
1197
            test->test_params.bulk.rx_delay_divisor, test->test_params.bulk.rx_delay_increment);
1198
 
1199
 
1200
    // That is all the data converted from Tcl to C, and a local thread is set up to handle this
1201
    // request. Also set up a thread on the target.
1202
    request_index = 0;
1203
    pack_usbtest_bulk(&(test->test_params.bulk), request, &request_index);
1204
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_BULK, 0, 0, request_index, request);
1205
    remote_thread_count++;
1206
 
1207
    return TCL_OK;
1208
}
1209
 
1210
/*}}}*/
1211
/*{{{  start control-in test                                    */
1212
 
1213
// ----------------------------------------------------------------------------
1214
// Start a control-in test. The real Tcl interface to this
1215
// functionality is implemented in Tcl: it takes care of figuring out
1216
// sensible default arguments, validating the data, etc. All that this
1217
// code does is allocate a thread and fill in the appropriate data,
1218
// plus request the target-side to do the same thing.
1219
 
1220
static int
1221
tcl_test_control_in(ClientData     clientData  __attribute__ ((unused)),
1222
                    Tcl_Interp*    interp,
1223
                    int            argc,
1224
                    char**         argv)
1225
{
1226
    int             i;
1227
    int             tmp;
1228
    UsbTest*        test;
1229
    unsigned char   request[USBTEST_MAX_CONTROL_DATA];
1230
    int             request_index;
1231
 
1232
    // The data consists of 6 numbers for UsbTest_ControlIn itself, and
1233
    // another 10 numbers for the test data definition.
1234
    if (17 != argc) {
1235
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_test_control_in <message>\"", TCL_STATIC);
1236
        return TCL_ERROR;
1237
    }
1238
    for (i = 1; i < 17; i++) {
1239
        int discard;
1240
        if (TCL_OK != Tcl_GetInt(interp, argv[i], &discard)) {
1241
            Tcl_SetResult(interp, "invalid argument: all arguments should be numbers", TCL_STATIC);
1242
            return TCL_ERROR;
1243
        }
1244
    }
1245
 
1246
    test                = pool_allocate();
1247
    test->which_test    = usbtest_control_in;
1248
    Tcl_GetInt(interp, argv[1], &(test->test_params.control_in.number_packets));
1249
    Tcl_GetInt(interp, argv[2], &(test->test_params.control_in.packet_size_initial));
1250
    Tcl_GetInt(interp, argv[3], &(test->test_params.control_in.packet_size_min));
1251
    Tcl_GetInt(interp, argv[4], &(test->test_params.control_in.packet_size_max));
1252
    Tcl_GetInt(interp, argv[5], &(test->test_params.control_in.packet_size_multiplier));
1253
    Tcl_GetInt(interp, argv[6], &(test->test_params.control_in.packet_size_increment));
1254
    Tcl_GetInt(interp, argv[7], &tmp);
1255
    test->test_params.bulk.data.format = (usbtestdata) tmp;
1256
    Tcl_GetInt(interp, argv[ 8], &(test->test_params.control_in.data.seed));
1257
    Tcl_GetInt(interp, argv[ 9], &(test->test_params.control_in.data.multiplier));
1258
    Tcl_GetInt(interp, argv[10], &(test->test_params.control_in.data.increment));
1259
    Tcl_GetInt(interp, argv[11], &(test->test_params.control_in.data.transfer_seed_multiplier));
1260
    Tcl_GetInt(interp, argv[12], &(test->test_params.control_in.data.transfer_seed_increment));
1261
    Tcl_GetInt(interp, argv[13], &(test->test_params.control_in.data.transfer_multiplier_multiplier));
1262
    Tcl_GetInt(interp, argv[14], &(test->test_params.control_in.data.transfer_multiplier_increment));
1263
    Tcl_GetInt(interp, argv[15], &(test->test_params.control_in.data.transfer_increment_multiplier));
1264
    Tcl_GetInt(interp, argv[16], &(test->test_params.control_in.data.transfer_increment_increment));
1265
 
1266
    // That is all the data converted from Tcl to C, and a local thread is set up to handle this
1267
    // request. Also set up a thread on the target.
1268
    request_index = 0;
1269
    pack_usbtest_control_in(&(test->test_params.control_in), request, &request_index);
1270
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_CONTROL_IN, 0, 0,
1271
                                 request_index, request);
1272
    remote_thread_count++;
1273
 
1274
    return TCL_OK;
1275
}
1276
 
1277
/*}}}*/
1278
/*{{{  Cancel the current batch of tests                        */
1279
 
1280
static int
1281
tcl_cancel(ClientData     clientData    __attribute__ ((unused)),
1282
           Tcl_Interp*    interp,
1283
           int            argc,
1284
           char**         argv          __attribute__ ((unused)) )
1285
{
1286
    if (1 != argc) {
1287
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::cancel\"", TCL_STATIC);
1288
        return TCL_ERROR;
1289
    }
1290
 
1291
    // Send the request on to the target.
1292
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_CANCEL, 0, 0, 0, (void*)0);
1293
 
1294
    // Now cancel all the local tests. This can be done by resetting the counter
1295
    // of allocated threads: no actual work will have been started yet.
1296
    local_thread_count = 0;
1297
 
1298
    // And synchronise with the target
1299
    if (!usb_sync(usb_master_fd, 30)) {
1300
        fprintf(stderr, "usbhost: error, target has failed to process test cancel request.\n");
1301
        exit(EXIT_FAILURE);
1302
 
1303
    }
1304
    remote_thread_count     = 0;
1305
 
1306
    return TCL_OK;
1307
}
1308
 
1309
/*}}}*/
1310
/*{{{  Run a batch of tests                                     */
1311
 
1312
// ----------------------------------------------------------------------------
1313
// This code does an awful lot of the hard work. Start with various utilities.
1314
 
1315
// Has the current batch finished as far as the local threads are concerned?
1316
static int
1317
local_batch_finished(void)
1318
{
1319
    int result = 1;
1320
    int i;
1321
 
1322
    for (i = 0; i < local_thread_count; i++) {
1323
        if (pool[i].running) {
1324
            result = 0;
1325
            break;
1326
        }
1327
    }
1328
    return result;
1329
}
1330
 
1331
// Has the current batch finished as far as remote threads are concerned?
1332
static int
1333
remote_batch_finished(void)
1334
{
1335
    char buf[1];
1336
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_FINISHED,
1337
                                 0, 0, 1, (void*) buf);
1338
    return buf[0];
1339
}
1340
 
1341
// Perform recovery for a thread on the target. This involves asking the
1342
// target for recovery information, then performing an appropriate
1343
// action. If no data is returned then no recovery is needed for this thread.
1344
static void
1345
recover_remote(int index)
1346
{
1347
    unsigned char       buffer[USBTEST_MAX_CONTROL_DATA];
1348
    int                 buffer_index;
1349
    UsbTest_Recovery    recovery;
1350
    int                 i;
1351
 
1352
    if (0 != usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
1353
                                          USBTEST_GET_RECOVERY, 0, index, 12, buffer)) {
1354
        // There is work to be done
1355
        buffer_index = 0;
1356
        unpack_usbtest_recovery(&recovery, buffer, &buffer_index);
1357
 
1358
        // We have an endpoint, a protocol, and a size.
1359
        if (0 == recovery.endpoint) {
1360
            // The target just needs a dummy reserved control message
1361
            usb_reliable_control_message(usb_master_fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE, USBTEST_RESERVED_CONTROL_IN,
1362
                                         0, 0, 0, (void*) 0);
1363
        } else if (USB_ENDPOINT_XFER_BULK == recovery.protocol) {
1364
            // Either we need to send some data to the target, or we need to accept some data.
1365
            static unsigned char recovery_buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];
1366
 
1367
            struct  usbdevfs_bulktransfer    transfer;
1368
            transfer.ep         = recovery.endpoint;
1369
            transfer.timeout    = 2000; // Two seconds.  Should be plenty, even for a large bulk transfer.
1370
            transfer.data       = recovery_buffer;
1371
            if (USB_DIR_IN == (recovery.endpoint & USB_ENDPOINT_DIR_MASK)) {
1372
                transfer.len = recovery.size;
1373
            } else {
1374
                transfer.len = 1;
1375
            }
1376
            errno = 0;
1377
            i = ioctl(usb_master_fd, USBDEVFS_BULK, &transfer);
1378
        }
1379
 
1380
        // There is no recovery support yet for other protocols.
1381
    }
1382
}
1383
 
1384
// Perform recovery for a local thread. This involves extracting the
1385
// recovery information from the local thread and asking the target
1386
// to take appropriate action.
1387
static void
1388
recover_local(int index)
1389
{
1390
    unsigned char   buffer[USBTEST_MAX_CONTROL_DATA];
1391
    int             buffer_index;
1392
 
1393
    if (pool[index].running) {
1394
        buffer_index = 0;
1395
        pack_usbtest_recovery(&(pool[index].test.recovery), buffer, &buffer_index);
1396
        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PERFORM_RECOVERY,
1397
                                     0, 0, buffer_index, (void*) buffer);
1398
    }
1399
}
1400
 
1401
// All done, time for a clean-up on both target and host. The latter
1402
// is achieved simply by resetting the thread pool, which actually
1403
// just means resetting the counter since all the threads are blocked
1404
// waiting for the next batch.
1405
static void
1406
run_done(void)
1407
{
1408
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_BATCH_DONE, 0, 0, 0, (void*) NULL);
1409
    local_thread_count = 0;
1410
    remote_thread_count = 0;
1411
}
1412
 
1413
// The main routine, as invoked from Tcl. This takes a single
1414
// argument, a timeout in seconds.
1415
static int
1416
tcl_run(ClientData     clientData    __attribute__ ((unused)),
1417
        Tcl_Interp*    interp,
1418
        int            argc,
1419
        char**         argv          __attribute__ ((unused)) )
1420
{
1421
    struct timespec delay;
1422
    int             timeout;
1423
    time_t          start;
1424
    time_t          now;
1425
    int             i, j;
1426
    unsigned char   result_buf[USBTEST_MAX_CONTROL_DATA];
1427
    int             all_ok;
1428
 
1429
    if (2 != argc) {
1430
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_run <timeout>\"", TCL_STATIC);
1431
        return TCL_ERROR;
1432
    }
1433
    if (TCL_OK != Tcl_GetInt(interp, argv[1], &timeout)) {
1434
        Tcl_SetResult(interp, "invalid argument: timeout should be numeric", TCL_STATIC);
1435
        return TCL_ERROR;
1436
    }
1437
 
1438
    VERBOSE(2, "Starting a testrun, timeout %d seconds\n", timeout);
1439
 
1440
    // Start the tests running on the target. The target USB hardware
1441
    // will not actually do anything except in response to packets
1442
    // from the host, so it is better to start the target before the
1443
    // local threads.
1444
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_START, 0, 0, 0, (void*) 0);
1445
 
1446
    // Now the local threads can get going.
1447
    current_tests_terminated = 0;
1448
    pool_start();
1449
 
1450
    // Now leave the various testing threads to do their thing until
1451
    // either side believes that the batch has finished, or until the
1452
    // timeout expires. Note that if one side decides that the batch
1453
    // has finished but the other disagrees, that in itself indicates
1454
    // a test failure of sorts.
1455
    //
1456
    // There is a question of polling frequency. Once a second avoids
1457
    // excessive polling traffic on the USB bus, and should not impose
1458
    // intolerable delays for short-duration tests.
1459
    start = time(NULL);
1460
    do {
1461
        VERBOSE(3, "The tests are running, waiting for termination\n");
1462
        delay.tv_sec    = 1;
1463
        delay.tv_nsec   = 0;
1464
        nanosleep(&delay, NULL);
1465
        now = time(NULL);
1466
    } while (((start + timeout) > now) && !local_batch_finished() && !remote_batch_finished());
1467
 
1468
    VERBOSE(2, "Termination detected, time elapsed %ld\n", (long) now - start);
1469
 
1470
    // If either side believes that testing is not complete, things
1471
    // get messy. Start by setting the terminated flag. Any tests that
1472
    // are actually still running happily but have not finished within
1473
    // the timeout should detect this and stop.
1474
    if (!local_batch_finished() || !remote_batch_finished()) {
1475
        VERBOSE(2, "Testing is not yet complete, setting TERMINATED flag\n");
1476
        current_tests_terminated    = 1;
1477
        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_SET_TERMINATED, 0, 0, 0, (void*) 0);
1478
        // And another delay, to give threads a chance to detect the
1479
        // flag's update
1480
        delay.tv_sec    = 1;
1481
        delay.tv_nsec   = 0;
1482
        nanosleep(&delay, NULL);
1483
    }
1484
 
1485
    // If there is still are unfinished threads, recovery action
1486
    // is needed. It is not clear whether it is better to unlock
1487
    // the local threads first, or the remote threads. For now the
1488
    // latter approach is taken.
1489
    if (!remote_batch_finished()) {
1490
        int i;
1491
        VERBOSE(2, "Remote threads still running, performing remote recovery\n");
1492
        for (i = 0; i < remote_thread_count; i++) {
1493
            recover_remote(i);
1494
        }
1495
        // Allow the recovery actions to take effect
1496
        delay.tv_sec    = 1;
1497
        delay.tv_nsec   = 0;
1498
        nanosleep(&delay, NULL);
1499
    }
1500
 
1501
    if (!local_batch_finished()) {
1502
        int i;
1503
        VERBOSE(2, "Local threads still running, performing local recovery\n");
1504
        for (i = 0; i < local_thread_count; i++) {
1505
            recover_local(i);
1506
        }
1507
        // Allow the recovery actions to take effect
1508
        delay.tv_sec    = 1;
1509
        delay.tv_nsec   = 0;
1510
        nanosleep(&delay, NULL);
1511
    }
1512
 
1513
    // One last check to make sure that everything is finished. If not,
1514
    // testing has broken down and it is necessary to abort.
1515
    if (!local_batch_finished() || !remote_batch_finished()) {
1516
        VERBOSE(2, "Giving local and remote threads another chance to finish.\n");
1517
        // Allow the recovery actions to take effect
1518
        delay.tv_sec    = 5;
1519
        delay.tv_nsec   = 0;
1520
        nanosleep(&delay, NULL);
1521
        if (!local_batch_finished() || !remote_batch_finished()) {
1522
            // OK, normality has not been restored.
1523
            // It would be nice to get hold of and display any error messages.
1524
            usb_abort(usb_master_fd);
1525
            fprintf(stderr, "Fatal error: the host test program and the remote target are out of synch.\n");
1526
            fprintf(stderr, "             recovery has been attempted, without success.\n");
1527
            fprintf(stderr, "             USB testing cannot continue.\n");
1528
            exit(EXIT_FAILURE);
1529
        }
1530
    }
1531
 
1532
    VERBOSE(2, "Local and remote threads are in synch, collecting results.\n");
1533
 
1534
    // The world is in a coherent state. Time to collect the results.
1535
    // The return value of this function is a simple boolean. More
1536
    // detailed results will be held in a Tcl variable as a list of
1537
    // messages. It is desirable to keep both local and remote results
1538
    // in order.
1539
    for (i = 0; i < ((local_thread_count < remote_thread_count) ? local_thread_count : remote_thread_count); i++) {
1540
        if (!pool[i].test.result_pass) {
1541
            Tcl_SetVar(interp, "usbtest::results", pool[i].test.result_message,
1542
                       all_ok ? (TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT) : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));
1543
            all_ok = 0;
1544
        }
1545
        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT,
1546
                                     0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf);
1547
        if (!result_buf[0]) {
1548
            Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]),
1549
                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));
1550
            all_ok = 0;
1551
        }
1552
    }
1553
    for (j = i; j < local_thread_count; j++) {
1554
        if (!pool[j].test.result_pass) {
1555
            Tcl_SetVar(interp, "usbtest::results", pool[j].test.result_message,
1556
                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));
1557
            all_ok = 0;
1558
        }
1559
    }
1560
    for (j = i; j < remote_thread_count; j++) {
1561
        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT,
1562
                                     0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf);
1563
        if (!result_buf[0]) {
1564
            Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]),
1565
                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));
1566
            all_ok = 0;
1567
        }
1568
    }
1569
    VERBOSE(2, "Overall test result %d\n", all_ok);
1570
 
1571
    Tcl_SetResult(interp, all_ok ? "1" : "0", TCL_STATIC);
1572
 
1573
    run_done();
1574
 
1575
    return TCL_OK;
1576
}
1577
 
1578
/*}}}*/
1579
/*{{{  Set verbosity                                            */
1580
 
1581
// ----------------------------------------------------------------------------
1582
// Allow Tcl scripts to control verbosity levels for both host and target
1583
static int
1584
tcl_host_verbose(ClientData     clientData    __attribute__ ((unused)),
1585
                  Tcl_Interp*    interp,
1586
                  int            argc,
1587
                  char**         argv)
1588
{
1589
    int level;
1590
 
1591
    if (2 != argc) {
1592
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::host_verbose <level>\"", TCL_STATIC);
1593
        return TCL_ERROR;
1594
    }
1595
    if (TCL_OK != Tcl_GetInt(interp, argv[1], &level)) {
1596
        Tcl_SetResult(interp, "invalid argument: verbosity level should be numeric", TCL_STATIC);
1597
        return TCL_ERROR;
1598
    }
1599
 
1600
    verbose = level;
1601
    return TCL_OK;
1602
}
1603
 
1604
static int
1605
tcl_target_verbose(ClientData     clientData    __attribute__ ((unused)),
1606
                   Tcl_Interp*    interp,
1607
                   int            argc,
1608
                   char**         argv)
1609
{
1610
    int level;
1611
 
1612
    if (2 != argc) {
1613
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_verbose <level>\"", TCL_STATIC);
1614
        return TCL_ERROR;
1615
    }
1616
    if (TCL_OK != Tcl_GetInt(interp, argv[1], &level)) {
1617
        Tcl_SetResult(interp, "invalid argument: verbosity level should be numeric", TCL_STATIC);
1618
        return TCL_ERROR;
1619
    }
1620
 
1621
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_VERBOSE, level, 0, 0, NULL);
1622
    usb_sync(usb_master_fd, -1);
1623
 
1624
    return TCL_OK;
1625
}
1626
 
1627
/*}}}*/
1628
 
1629
/*}}}*/
1630
/*{{{  AppInit()                                                */
1631
 
1632
// ----------------------------------------------------------------------------
1633
// Application-specific initialization. We have a bare Tcl interpreter ready
1634
// to start executing scripts that define various test cases. However some
1635
// additional functions will have to be added to the interpreter, plus
1636
// information about the various endpoints.
1637
 
1638
static int
1639
usbhost_appinit(Tcl_Interp* interp)
1640
{
1641
    unsigned char   buf[USBTEST_MAX_CONTROL_DATA];
1642
    int             number_of_endpoints;
1643
    int             i;
1644
    char*           location;
1645
 
1646
    // Start by creating a usbtest namespace, for use by the various functions
1647
    // and variables.
1648
    if (TCL_OK != Tcl_Eval(interp,
1649
                           "namespace eval usbtest {\n"
1650
                           "    variable number_of_endpoints 0\n"
1651
                           "    array set endpoint [list]\n"
1652
                           "}\n")) {
1653
        fprintf(stderr, "usbhost: internal error, failed to create Tcl usbtest:: namespace\n");
1654
        fprintf(stderr, "         Please check Tcl version (8.0b1 or later required).\n");
1655
        exit(EXIT_FAILURE);
1656
    }
1657
 
1658
    // Add some information about the install path so that the
1659
    // main Tcl script can find and execute test scripts.
1660
    location = getenv("USBHOSTDIR");
1661
    if (NULL == location) {
1662
        location = USBAUXDIR;
1663
    }
1664
    Tcl_SetVar(interp, "usbtest::USBAUXDIR", location, TCL_GLOBAL_ONLY);
1665
 
1666
    // Also set the verbosity level correctly
1667
    Tcl_SetVar2Ex(interp, "usbtest::verbose", NULL, Tcl_NewIntObj(verbose), TCL_GLOBAL_ONLY);
1668
 
1669
    // Next we need to know the number of endpoints, and for each
1670
    // endpoint we want additional information such as type. The
1671
    // results are placed in a Tcl array.
1672
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_ENDPOINT_COUNT,
1673
                                 0, 0, 1, buf);
1674
    number_of_endpoints = buf[0];
1675
    Tcl_SetVar2Ex(interp, "usbtest::endpoint_count", NULL, Tcl_NewIntObj(number_of_endpoints), TCL_GLOBAL_ONLY);
1676
 
1677
    for (i = 0; i < number_of_endpoints; i++) {
1678
        char            varname[256];
1679
        int             result;
1680
        int             endpoint_min_size;
1681
        int             endpoint_max_size;
1682
        int             index;
1683
 
1684
        memset(buf, 0, USBTEST_MAX_CONTROL_DATA);
1685
        result = usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,
1686
                                              USBTEST_ENDPOINT_DETAILS, 0, i, USBTEST_MAX_CONTROL_DATA, buf);
1687
        if (result < 13) {
1688
            fprintf(stderr, "usbhost: error, received insufficient endpoint data back from the target.\n");
1689
            exit(EXIT_FAILURE);
1690
        }
1691
 
1692
        // See protocol.h for the encoding used.
1693
        sprintf(varname, "usbtest::endpoint_data(%d,type)", i);
1694
        switch(buf[0]) {
1695
          case USB_ENDPOINT_XFER_CONTROL    : Tcl_SetVar(interp, varname, "control",     TCL_GLOBAL_ONLY); break;
1696
          case USB_ENDPOINT_XFER_ISOC       : Tcl_SetVar(interp, varname, "isochronous", TCL_GLOBAL_ONLY); break;
1697
          case USB_ENDPOINT_XFER_BULK       : Tcl_SetVar(interp, varname, "bulk",        TCL_GLOBAL_ONLY); break;
1698
          case USB_ENDPOINT_XFER_INT        : Tcl_SetVar(interp, varname, "interrupt",   TCL_GLOBAL_ONLY); break;
1699
        }
1700
 
1701
        sprintf(varname, "usbtest::endpoint_data(%d,number)", i);
1702
        Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj((int) buf[1]), TCL_GLOBAL_ONLY);
1703
 
1704
        sprintf(varname, "usbtest::endpoint_data(%d,direction)", i);
1705
        if (USB_DIR_OUT == buf[2]) {
1706
            Tcl_SetVar(interp, varname, "out", TCL_GLOBAL_ONLY);
1707
        } else {
1708
            Tcl_SetVar(interp, varname, "in", TCL_GLOBAL_ONLY);
1709
        }
1710
 
1711
        sprintf(varname, "usbtest::endpoint_data(%d,max_in_padding)", i);
1712
        Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj((int) buf[3]), TCL_GLOBAL_ONLY);
1713
 
1714
        sprintf(varname, "usbtest::endpoint_data(%d,min_size)", i);
1715
        index               = 4;
1716
        endpoint_min_size   = unpack_int(buf, &index);
1717
        Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj(endpoint_min_size), TCL_GLOBAL_ONLY);
1718
 
1719
        sprintf(varname, "usbtest::endpoint_data(%d,max_size)", i);
1720
        endpoint_max_size   = unpack_int(buf, &index);
1721
        if (USB_ENDPOINT_XFER_CONTROL == buf[0]) {
1722
            if (endpoint_max_size > USBTEST_MAX_CONTROL_DATA) {
1723
                endpoint_max_size = USBTEST_MAX_CONTROL_DATA;
1724
            }
1725
        } else {
1726
            if ((-1 == endpoint_max_size) || (endpoint_max_size > USBTEST_MAX_BULK_DATA)) {
1727
                endpoint_max_size = USBTEST_MAX_BULK_DATA;
1728
            }
1729
        }
1730
        Tcl_SetVar2Ex(interp, varname, NULL, Tcl_NewIntObj(endpoint_max_size), TCL_GLOBAL_ONLY);
1731
 
1732
        sprintf(varname, "usbtest::endpoint_data(%d,devtab)", i);
1733
        Tcl_SetVar(interp, varname, (char*) &(buf[12]), TCL_GLOBAL_ONLY);
1734
 
1735
        // Perform any additional endpoint-specific initialization to make
1736
        // sure host and target can actually communicate via this endpoint.
1737
        switch(buf[0]) {
1738
          case USB_ENDPOINT_XFER_CONTROL    :
1739
          {
1740
              usb_initialise_control_endpoint(endpoint_min_size, endpoint_max_size);
1741
              break;
1742
          }
1743
          case USB_ENDPOINT_XFER_ISOC       :
1744
          {
1745
              if (USB_DIR_OUT == buf[2]) {
1746
                  usb_initialise_isochronous_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size);
1747
              } else {
1748
                  usb_initialise_isochronous_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size);
1749
              }
1750
              break;
1751
          }
1752
          case USB_ENDPOINT_XFER_BULK       :
1753
          {
1754
              if (USB_DIR_OUT == buf[2]) {
1755
                  usb_initialise_bulk_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size);
1756
              } else {
1757
                  usb_initialise_bulk_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size, buf[3]);
1758
              }
1759
 
1760
              break;
1761
          }
1762
          case USB_ENDPOINT_XFER_INT        :
1763
          {
1764
              if (USB_DIR_OUT == buf[2]) {
1765
                  usb_initialise_interrupt_out_endpoint(buf[1], endpoint_min_size, endpoint_max_size);
1766
              } else {
1767
                  usb_initialise_interrupt_in_endpoint(buf[1], endpoint_min_size, endpoint_max_size);
1768
              }
1769
              break;
1770
          }
1771
        }
1772
    }
1773
 
1774
    // Register appropriate commands with the Tcl interpreter
1775
    Tcl_CreateCommand(interp, "usbtest::target_pass",       &tcl_target_pass,       (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1776
    Tcl_CreateCommand(interp, "usbtest::target_pass_exit",  &tcl_target_pass_exit,  (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1777
    Tcl_CreateCommand(interp, "usbtest::target_fail",       &tcl_target_fail,       (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1778
    Tcl_CreateCommand(interp, "usbtest::target_fail_exit",  &tcl_target_fail_exit,  (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1779
    Tcl_CreateCommand(interp, "usbtest::target_abort",      &tcl_target_abort,      (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1780
    Tcl_CreateCommand(interp, "usbtest::_test_bulk",        &tcl_test_bulk,         (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1781
    Tcl_CreateCommand(interp, "usbtest::_test_control_in",  &tcl_test_control_in,   (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1782
    Tcl_CreateCommand(interp, "usbtest::_cancel",           &tcl_cancel,            (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1783
    Tcl_CreateCommand(interp, "usbtest::_run",              &tcl_run,               (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1784
    Tcl_CreateCommand(interp, "usbtest::host_verbose",      &tcl_host_verbose,      (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1785
    Tcl_CreateCommand(interp, "usbtest::target_verbose",    &tcl_target_verbose,    (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
1786
 
1787
    return TCL_OK;
1788
}
1789
 
1790
/*}}}*/
1791
/*{{{  main()                                                   */
1792
 
1793
// ----------------------------------------------------------------------------
1794
// System start-up. After argument processing this code checks that
1795
// there is a suitable USB target attached - if not then there is no
1796
// point in proceeding. Otherwise further initialization is performed
1797
// and then control is passed to a Tcl interpreter.
1798
 
1799
static void
1800
usage(void)
1801
{
1802
    printf("usbhost: usage, usbhost [-V|--verbose] [-v|--version] [-h|--help] <test> [args]\n");
1803
    printf("    -V, --verbose    Make the host-side output additional information\n");
1804
    printf("                     during test runs. This argument can be repeated to\n");
1805
    printf("                     increase verbosity.\n");
1806
    printf("    -v, --version    Output version information for usbhost.\n");
1807
    printf("    -h, --help       Output this help information.\n");
1808
    printf("    <test>           The name of a USB test case, for example list.tcl\n");
1809
    printf("    [args]           Optional additional arguments for the testcase.\n");
1810
    exit(0);
1811
}
1812
 
1813
static void
1814
version(void)
1815
{
1816
    printf("usbhost: version %s\n", USBHOST_VERSION);
1817
    printf("       : built from USB slave package version %s\n", PKGVERSION);
1818
    printf("       : support files installed in %s\n", USBAUXDIR);
1819
    exit(0);
1820
}
1821
 
1822
int
1823
main(int argc, char** argv)
1824
{
1825
    char*   interpreter = argv[0];
1826
    char**  new_argv;
1827
    char    path[_POSIX_PATH_MAX];
1828
    char*   location;
1829
    int     i;
1830
 
1831
    // Argument processing
1832
    for (i = 1; i < argc; i++) {
1833
        if ((0 == strcmp("-h", argv[i])) || (0 == strcmp("-H", argv[i])) || (0 == strcmp("--help", argv[i]))) {
1834
            usage();
1835
        }
1836
        if ((0 == strcmp("-v", argv[i])) || (0 == strcmp("--version", argv[i]))) {
1837
            version();
1838
        }
1839
        if ((0 == strcmp("-V", argv[i])) || (0 == strcmp("--verbose", argv[i]))) {
1840
            verbose++;
1841
            continue;
1842
        }
1843
 
1844
        // The first unrecognised argument should correspond to the test script.
1845
        break;
1846
    }
1847
    argc  = (argc - i) + 1;
1848
    argv  = (argv + i) - 1;
1849
 
1850
    if (1 == argc) {
1851
        fprintf(stderr, "usbhost: at least one test script must be specified on the command line.\n");
1852
        exit(EXIT_FAILURE);
1853
    }
1854
 
1855
    usb_master_fd = usb_open_device();
1856
    if (-1 == usb_master_fd) {
1857
        return EXIT_FAILURE;
1858
    }
1859
 
1860
    // There is a valid USB target. Initialize the pool of threads etc.
1861
    pool_initialize();
1862
 
1863
    // Now start a Tcl interpreter. Tcl_Main() will interpret the
1864
    // first argument as the name of a Tcl script to execute,
1865
    // i.e. usbhost.tcl. This can be found in the install tree,
1866
    // but during development it is inconvenient to run
1867
    // "make install" every time the Tcl script is edited so an
1868
    // environment variable can be used to override the location.
1869
    new_argv = malloc((argc + 2) * sizeof(char*));
1870
    if (NULL == new_argv) {
1871
        fprintf(stderr, "usbhost: internal error, out of memory.\n");
1872
        exit(EXIT_FAILURE);
1873
    }
1874
    new_argv[0] = interpreter;
1875
 
1876
    location = getenv("USBHOSTDIR");
1877
    if (NULL == location) {
1878
        location = USBAUXDIR;
1879
    }
1880
    snprintf(path, _POSIX_PATH_MAX, "%s/usbhost.tcl", location);
1881
    if (0 != access(path, R_OK)) {
1882
        fprintf(stderr, "usbhost: cannot find or access required Tcl script\n");
1883
        fprintf(stderr, "       : %s\n", path);
1884
        exit(EXIT_FAILURE);
1885
    }
1886
    new_argv[1] = path;
1887
 
1888
    for (i = 1; i < argc; i++) {
1889
        new_argv[i+1] = argv[i];
1890
    }
1891
    new_argv[i+1]   = NULL;
1892
 
1893
    Tcl_Main(i+1, new_argv, &usbhost_appinit);
1894
 
1895
    return EXIT_SUCCESS;
1896
}
1897
 
1898
/*}}}*/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.