📄 usbhost.c
字号:
buf[j], buf[j+1], buf[j+2], buf[j+3]);
}
if (j < 32) {
index += snprintf(msg+index, 255-index, " ");
for ( ; j < packet_size; j++) {
index += snprintf(msg+index, 255-index, "%02x", buf[j]);
}
}
VERBOSE(3, "%s\n", msg);
}
transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, packet_size);
// Has this test run been aborted for some reason?
if (current_tests_terminated) {
VERBOSE(2, "Bulk OUT test %d: iteration %d, termination detected\n", test->id, i);
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk OUT transfer on endpoint %d: aborted after %d iterations\n",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i);
return;
}
// If an error occurred, abort this run.
if (-1 == transferred) {
char errno_buf[USBTEST_MAX_MESSAGE];
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk OUT transfer on endpoint %d : host ioctl() system call failed\n errno %d (%s)",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno,
strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
VERBOSE(2, "Bulk OUT test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message);
break;
}
if (0 != test->test_params.bulk.tx_delay) {
struct timespec delay;
VERBOSE(2, "Bulk OUT test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \
i, test->test_params.bulk.tx_delay);
// Note that nanosleep() can return early due to incoming signals,
// with the unelapsed time returned in a second argument. This
// allows for a retry loop. In practice this does not seem
// worthwhile, the delays are approximate anyway.
delay.tv_sec = test->test_params.bulk.tx_delay / 1000000000;
delay.tv_nsec = test->test_params.bulk.tx_delay % 1000000000;
nanosleep(&delay, NULL);
}
// Now move on to the next transfer
USBTEST_BULK_NEXT(test->test_params.bulk);
}
// If all the packets have been transferred this test has passed.
if (i >= test->test_params.bulk.number_packets) {
test->result_pass = 1;
}
VERBOSE(1, "Test %d bulk OUT on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass);
}
/*}}}*/
/*{{{ bulk IN */
static void
run_test_bulk_in(UsbTest* test)
{
unsigned char* buf = test->buffer;
int i;
VERBOSE(1, "Starting test %d bulk IN on endpoint %d\n", test->id, test->test_params.bulk.endpoint);
for (i = 0; i < test->test_params.bulk.number_packets; i++) {
int transferred;
int tx_size = test->test_params.bulk.tx_size;
int rx_size = test->test_params.bulk.rx_size;
int size_plus_padding;
VERBOSE(2, "Bulk IN test %d: iteration %d, rx size %d, tx size %d\n", test->id, i, rx_size, tx_size);
if (rx_size < tx_size) {
rx_size = tx_size;
VERBOSE(2, "Bulk IN test %d: iteration %d, packet size reset to %d to match tx size\n",
test->id, i, rx_size);
}
test->recovery.endpoint = test->test_params.bulk.endpoint;
test->recovery.protocol = USB_ENDPOINT_XFER_BULK;
test->recovery.size = rx_size;
// Make sure there is no old data lying around
if (usbtestdata_none != test->test_params.bulk.data.format) {
memset(buf, 0, rx_size);
}
// And do the actual transfer.
size_plus_padding = rx_size;
if (size_plus_padding < (tx_size + test->test_params.bulk.rx_padding)) {
size_plus_padding += test->test_params.bulk.rx_padding;
}
do {
transferred = usb_bulk_message(test->fd, test->test_params.bulk.endpoint, buf, size_plus_padding);
} while (0 == transferred);
// Has this test run been aborted for some reason?
if (current_tests_terminated) {
VERBOSE(2, "Bulk IN test %d: iteration %d, termination detected\n", test->id, i);
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk IN transfer on endpoint %d: aborted after %d iterations\n",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, i);
return;
}
// If an error occurred, abort this run.
if (-1 == transferred) {
char errno_buf[USBTEST_MAX_MESSAGE];
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk IN transfer on endpoint %d : host ioctl() system call failed\n errno %d (%s)",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, errno,
strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message);
break;
}
// Did the target send the expected amount of data?
if (transferred < tx_size) {
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk IN transfer on endpoint %d : the target only sent %d bytes when %d were expected",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK, transferred, tx_size);
VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message);
break;
}
if (verbose >= 3) {
// Output the first 32 bytes of data
char msg[256];
int index;
int j;
index = snprintf(msg, 255, "Bulk IN test %d: iteration %d, transferred %d\n Data %s:",
test->id, i, transferred,
(usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : "");
for (j = 0; ((j + 3) < transferred) && (j < 32); j+= 4) {
index += snprintf(msg+index, 255-index, " %02x%02x%02x%02x",
buf[j], buf[j+1], buf[j+2], buf[j+3]);
}
if (j < 32) {
index += snprintf(msg+index, 255-index, " ");
for ( ; j < transferred; j++) {
index += snprintf(msg+index, 255-index, "%02x", buf[j]);
}
}
VERBOSE(3, "%s\n", msg);
}
// Is the data correct?
if (!usbtest_check_buffer(&(test->test_params.bulk.data), buf, tx_size)) {
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, bulk IN transfer on endpoint %d : mismatch between received and expected data",
test->test_params.bulk.endpoint & USB_ENDPOINT_NUMBER_MASK);
VERBOSE(2, "Bulk IN test %d: iteration %d, error:\n %s\n", test->id, i, test->result_message);
break;
}
if (0 != test->test_params.bulk.rx_delay) {
struct timespec delay;
VERBOSE(2, "Bulk IN test %d: iteration %d, sleeping for %d nanoseconds\n", test->id, \
i, test->test_params.bulk.tx_delay);
// Note that nanosleep() can return early due to incoming signals,
// with the unelapsed time returned in a second argument. This
// allows for a retry loop. In practice this does not seem
// worthwhile, the delays are approximate anyway.
delay.tv_sec = test->test_params.bulk.rx_delay / 1000000000;
delay.tv_nsec = test->test_params.bulk.rx_delay % 1000000000;
nanosleep(&delay, NULL);
}
USBTEST_BULK_NEXT(test->test_params.bulk);
}
// If all the packets have been transferred this test has passed.
if (i >= test->test_params.bulk.number_packets) {
test->result_pass = 1;
}
VERBOSE(1, "Test %d bulk IN on endpoint %d, result %d\n", test->id, test->test_params.bulk.endpoint, test->result_pass);
}
/*}}}*/
/*{{{ control IN */
// Receive appropriate packets via the control endpoint. This is somewhat
// different from bulk transfers. It is implemented using reserved control
// messages.
//
// Note: it is not entirely clear that this test is safe. There will be
// concurrent control traffic to detect test termination and the like,
// and these control messages may interfere with each other. It is not
// entirely clear how the Linux kernel handles concurrent control
// operations.
static void
run_test_control_in(UsbTest* test)
{
unsigned char* buf = test->buffer;
int packet_size;
int i;
packet_size = test->test_params.control_in.packet_size_initial;
for (i = 0; i < test->test_params.control_in.number_packets; i++) {
int transferred;
test->recovery.endpoint = 0;
test->recovery.protocol = USB_ENDPOINT_XFER_CONTROL;
test->recovery.size = packet_size;
// Make sure there is no old data lying around
if (usbtestdata_none != test->test_params.control_in.data.format) {
memset(buf, 0, packet_size);
}
// And do the actual transfer.
transferred = usb_control_message(test->fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_RESERVED_CONTROL_IN,
0, 0, packet_size, buf);
// Has this test run been aborted for some reason?
if (current_tests_terminated) {
return;
}
// If an error occurred, abort this run.
if (-1 == transferred) {
char errno_buf[USBTEST_MAX_MESSAGE];
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, control IN transfer: host ioctl() system call failed\n errno %d (%s)",
errno, strerror_r(errno, errno_buf, USBTEST_MAX_MESSAGE));
break;
}
// Did the target send the expected amount of data?
if (transferred < packet_size) {
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, control IN transfer: the target only sent %d bytes when %d were expected",
transferred, packet_size);
break;
}
// Is the data correct?
if (!usbtest_check_buffer(&(test->test_params.control_in.data), buf, packet_size)) {
test->result_pass = 0;
snprintf(test->result_message, USBTEST_MAX_MESSAGE,
"Host, control IN transfer: mismatch between received and expected data");
break;
}
USBTEST_CONTROL_NEXT_PACKET_SIZE(packet_size, test->test_params.control_in);
}
// If all the packets have been transferred this test has passed.
if (i >= test->test_params.control_in.number_packets) {
test->result_pass = 1;
}
}
/*}}}*/
// FIXME: add more tests
/*{{{ run_test() */
// This utility is invoked from a thread in the thread pool whenever there is
// work to be done. It simply dispatches to the appropriate handler.
static void
run_test(UsbTest* test)
{
switch (test->which_test) {
case usbtest_bulk_out: run_test_bulk_out(test); break;
case usbtest_bulk_in: run_test_bulk_in(test); break;
case usbtest_control_in: run_test_control_in(test); break;
default:
fprintf(stderr, "usbhost: internal error, attempt to execute an unknown test.\n");
exit(EXIT_FAILURE);
}
}
/*}}}*/
/*}}}*/
/*{{{ The thread pool */
// ----------------------------------------------------------------------------
// A pool of threads and buffers which do the real work. The number of possible
// concurrent tests is defined in protocol.h. Each one requires a separate
// thread, transfer buffer, semaphore, and some state information.
//
// Although the application is multi-threaded, in practice there is little
// need for synchronization. Tests will only be started while the pool threads
// are idle. When the pool threads are running the main thread will be waiting
// for them all to finish, with a bit of polling to detect error conditions.
// The pool threads do not share any data, apart from the file descriptor for
// the USB device.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -