📄 usbhost.c
字号:
// 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 voidrun_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 voidrun_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 voidrun_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.typedef struct PoolEntry { pthread_t thread; sem_t wakeup; int running; UsbTest test;} PoolEntry;static PoolEntry pool[USBTEST_MAX_CONCURRENT_TESTS];// This is the entry point for every thread in the pool. It just loops forever,// waiting until it is supposed to run a test. These threads never actually// exit, instead there should be a call to exit() somewhere.static void*pool_function(void* arg){ PoolEntry* pool_entry = (PoolEntry*) arg; for ( ; ; ) { sem_wait(&(pool_entry->wakeup)); run_test(&(pool_entry->test)); pool_entry->running = 0; } return NULL;}// Initialize all threads in the pool.static voidpool_initialize(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -