You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
5.8 KiB
212 lines
5.8 KiB
/* |
|
* Copyright (C) 2008 The Android Open Source Project |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* * Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* * Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in |
|
* the documentation and/or other materials provided with the |
|
* distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <errno.h> |
|
|
|
#include <sys/time.h> |
|
|
|
#include "usb.h" |
|
|
|
static unsigned arg_size = 4096; |
|
static unsigned arg_count = 4096; |
|
|
|
long long NOW(void) |
|
{ |
|
struct timeval tv; |
|
gettimeofday(&tv, 0); |
|
|
|
return (((long long) tv.tv_sec) * ((long long) 1000000)) + |
|
(((long long) tv.tv_usec)); |
|
} |
|
|
|
int printifc(usb_ifc_info *info) |
|
{ |
|
printf("dev: csp=%02x/%02x/%02x v=%04x p=%04x ", |
|
info->dev_class, info->dev_subclass, info->dev_protocol, |
|
info->dev_vendor, info->dev_product); |
|
printf("ifc: csp=%02x/%02x/%02x%s%s\n", |
|
info->ifc_class, info->ifc_subclass, info->ifc_protocol, |
|
info->has_bulk_in ? " in" : "", |
|
info->has_bulk_out ? " out" : ""); |
|
return -1; |
|
} |
|
|
|
int match_null(usb_ifc_info *info) |
|
{ |
|
if(info->dev_vendor != 0x18d1) return -1; |
|
if(info->ifc_class != 0xff) return -1; |
|
if(info->ifc_subclass != 0xfe) return -1; |
|
if(info->ifc_protocol != 0x01) return -1; |
|
return 0; |
|
} |
|
|
|
int match_zero(usb_ifc_info *info) |
|
{ |
|
if(info->dev_vendor != 0x18d1) return -1; |
|
if(info->ifc_class != 0xff) return -1; |
|
if(info->ifc_subclass != 0xfe) return -1; |
|
if(info->ifc_protocol != 0x02) return -1; |
|
return 0; |
|
} |
|
|
|
int match_loop(usb_ifc_info *info) |
|
{ |
|
if(info->dev_vendor != 0x18d1) return -1; |
|
if(info->ifc_class != 0xff) return -1; |
|
if(info->ifc_subclass != 0xfe) return -1; |
|
if(info->ifc_protocol != 0x03) return -1; |
|
return 0; |
|
} |
|
|
|
int test_null(Transport* usb) |
|
{ |
|
unsigned i; |
|
unsigned char buf[4096]; |
|
memset(buf, 0xee, 4096); |
|
long long t0, t1; |
|
|
|
t0 = NOW(); |
|
for (i = 0; i < arg_count; i++) { |
|
if (usb->Write(buf, arg_size) != static_cast<int>(arg_size)) { |
|
fprintf(stderr,"write failed (%s)\n", strerror(errno)); |
|
return -1; |
|
} |
|
} |
|
t1 = NOW(); |
|
fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0)); |
|
return 0; |
|
} |
|
|
|
int test_zero(Transport* usb) |
|
{ |
|
unsigned i; |
|
unsigned char buf[4096]; |
|
long long t0, t1; |
|
|
|
t0 = NOW(); |
|
for (i = 0; i < arg_count; i++) { |
|
if (usb->Read(buf, arg_size) != static_cast<int>(arg_size)) { |
|
fprintf(stderr,"read failed (%s)\n", strerror(errno)); |
|
return -1; |
|
} |
|
} |
|
t1 = NOW(); |
|
fprintf(stderr,"%d bytes in %lld uS\n", arg_count * arg_size, (t1 - t0)); |
|
return 0; |
|
} |
|
|
|
struct |
|
{ |
|
const char *cmd; |
|
ifc_match_func match; |
|
int (*test)(Transport* usb); |
|
const char *help; |
|
} tests[] = { |
|
{ "list", printifc, NULL, "list interfaces" }, |
|
{ "send", match_null, test_null, "send to null interface" }, |
|
{ "recv", match_zero, test_zero, "recv from zero interface" }, |
|
{ "loop", match_loop, NULL, "exercise loopback interface" }, |
|
{ NULL, NULL, NULL, NULL }, |
|
}; |
|
|
|
int usage(void) |
|
{ |
|
int i; |
|
|
|
fprintf(stderr,"usage: usbtest <testname>\n\navailable tests:\n"); |
|
for(i = 0; tests[i].cmd; i++) { |
|
fprintf(stderr," %-8s %s\n", tests[i].cmd, tests[i].help); |
|
} |
|
return -1; |
|
} |
|
|
|
int process_args(int argc, char **argv) |
|
{ |
|
while(argc-- > 0) { |
|
char *arg = *argv++; |
|
if(!strncmp(arg,"count=",6)) { |
|
arg_count = atoi(arg + 6); |
|
} else if(!strncmp(arg,"size=",5)) { |
|
arg_size = atoi(arg + 5); |
|
} else { |
|
fprintf(stderr,"unknown argument: %s\n", arg); |
|
return -1; |
|
} |
|
} |
|
|
|
if(arg_count == 0) { |
|
fprintf(stderr,"count may not be zero\n"); |
|
return -1; |
|
} |
|
|
|
if(arg_size > 4096) { |
|
fprintf(stderr,"size may not be greater than 4096\n"); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
Transport* usb; |
|
int i; |
|
|
|
if(argc < 2) |
|
return usage(); |
|
|
|
if(argc > 2) { |
|
if(process_args(argc - 2, argv + 2)) |
|
return -1; |
|
} |
|
|
|
for(i = 0; tests[i].cmd; i++) { |
|
if(!strcmp(argv[1], tests[i].cmd)) { |
|
usb = usb_open(tests[i].match); |
|
if(tests[i].test) { |
|
if(usb == 0) { |
|
fprintf(stderr,"usbtest: %s: could not find interface\n", |
|
tests[i].cmd); |
|
return -1; |
|
} |
|
if(tests[i].test(usb)) { |
|
fprintf(stderr,"usbtest: %s: FAIL\n", tests[i].cmd); |
|
return -1; |
|
} else { |
|
fprintf(stderr,"usbtest: %s: OKAY\n", tests[i].cmd); |
|
} |
|
} |
|
return 0; |
|
} |
|
} |
|
|
|
return usage(); |
|
}
|
|
|