📄 usbhost.c
字号:
switch (this_len) { case 1: transfer.request = USBTEST_CONTROL_DATA1; break; case 2: transfer.request = USBTEST_CONTROL_DATA2; break; case 3: transfer.request = USBTEST_CONTROL_DATA3; break; case 4: transfer.request = USBTEST_CONTROL_DATA4; break; default: fprintf(stderr, "usbhost: internal error, confusion about transfer length.\n"); exit(EXIT_FAILURE); } transfer.value = (buf[i] << 8) | buf[i+1]; // Possible read beyond end of buffer, transfer.index = (buf[i+2] << 8) | buf[i+3]; // but not worth worrying about. transfer.length = 0; transfer.timeout = 10 * 1000; // ten seconds, the target should always accept data faster than this. transfer.data = NULL; // This is too strict, deciding what to do about errors should be // handled by higher-level code. However it will do for now. ioctl_result = ioctl(fd, USBDEVFS_CONTROL, &transfer); if (0 != ioctl_result) { fprintf(stderr, "usbhost: error, failed to send control message (data) to target.\n"); exit(EXIT_FAILURE); } } // There is no more data to be transferred. length = 0; }#endif transfer.requesttype = request_type; transfer.request = request; transfer.value = value; transfer.index = index; transfer.length = length; transfer.timeout = 10000; transfer.data = data; result = ioctl(fd, USBDEVFS_CONTROL, &transfer); return result;}// A variant of the above which can be called when the target should always respond// correctly. This can be used for class control messages.static intusb_reliable_control_message(int fd, int request_type, int request, int value, int index, int length, void* data){ int result = usb_control_message(fd, request_type, request, value, index, length, data); if (-1 == result) { fprintf(stderr, "usbhost: error, failed to send control message %02x to target.\n", request); fprintf(stderr, " : errno %d (%s)\n", errno, strerror(errno)); exit(EXIT_FAILURE); } return result;} // Either send or receive a single bulk message. The top bit of the endpoint// number indicates the direction.static intusb_bulk_message(int fd, int endpoint, unsigned char* buffer, int length){ struct usbdevfs_bulktransfer transfer; int result; transfer.ep = endpoint; transfer.len = length; transfer.timeout = 60 * 60 * 1000; // An hour. These operations should not time out because that // leaves the system in a confused state. Instead there is // higher-level recovery code that should ensure the operation // really does complete, and the return value here is used // by the calling code to determine whether the operation // was successful or whether there was an error and the recovery // code was invoked. transfer.data = buffer; errno = 0; result = ioctl(fd, USBDEVFS_BULK, &transfer); return result;}// Synchronise with the target. This can be used after the host has sent a request that// may take a bit of time, e.g. it may involve waking up a thread. The host will send// synch requests at regular intervals, until the target is ready.//// The limit argument can be used to avoid locking up. -1 means loop forever, otherwise// it means that many iterations of 100ms apiece.static intusb_sync(int fd, int limit){ unsigned char buf[1]; struct timespec delay; int loops = 0; int result = 0; VERBOSE(2, "Synchronizing with target\n"); while (1) { buf[0] = 0; usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_SYNCH, 0, 0, 1, buf); if (buf[0]) { result = 1; break; } else { if ((-1 != limit) && (++loops > limit)) { break; } else { VERBOSE(3, "Not yet synchronized, sleeping\n"); delay.tv_sec = 0; delay.tv_nsec = 100000000; // 100 ms nanosleep(&delay, NULL); } } } VERBOSE(2, "%s\n", result ? "Synchronized" : "Not synchronized"); return result;}// Abort the target. Things seem to be completely messed up and there is no easy// way to restore sanity to both target and host.static voidusb_abort(int fd){ VERBOSE(2, "Target-side abort operation invoked\n"); usb_reliable_control_message(fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_ABORT, 0, 0, 0, (void*)0);}/*}}}*//*{{{ Initialise endpoints */// ----------------------------------------------------------------------------// On power-up some endpoints may not be in a sensible state. For example,// with the SA11x0 the hardware may start accepting bulk OUT transfers// before the target-side software has started a receive operation,// so if the host sends a bulk packet before the target is ready then// things get messy. This is especially troublesome if the target-side// attempts any diagnostic output because of verbosity.//// This code loops through the various endpoints and makes sure that// they are all in a reasonable state, before any real tests get run// That means known hardware flaws do not show up as test failures,// but of course they are still documented and application software// will have to do the right thing.static voidusb_initialise_control_endpoint(int min_size, int max_size){ // At this time there are no known problems on any hardware // that would need to be addressed}static voidusb_initialise_isochronous_in_endpoint(int number, int min_size, int max_size){ // At this time there are no known problems on any hardware // that would need to be addressed}static voidusb_initialise_isochronous_out_endpoint(int number, int min_size, int max_size){ // At this time there are no known problems on any hardware // that would need to be addressed}static voidusb_initialise_bulk_in_endpoint(int number, int min_size, int max_size, int padding){ // At this time there are no known problems on any hardware // that would need to be addressed}static voidusb_initialise_bulk_out_endpoint(int number, int min_size, int max_size){ char buf[1]; // On the SA1110 the hardware comes up with a bogus default value, // causing the hardware to accept packets before the software has // set up DMA or in any way prepared for incoming data. This is // a problem. It is worked around by making the target receive // a single packet, sending that packet, and then performing a // sync. VERBOSE(2, "Performing bulk OUT initialization on endpoint %d\n", number); usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_INIT_BULK_OUT, number, 0, 0, (void*) 0); usb_bulk_message(usb_master_fd, number, buf, 1); usb_sync(usb_master_fd, 10);}static voidusb_initialise_interrupt_in_endpoint(int number, int min_size, int max_size){ // At this time there are no known problems on any hardware // that would need to be addressed}static voidusb_initialise_interrupt_out_endpoint(int number, int min_size, int max_size){ // At this time there are no known problems on any hardware // that would need to be addressed}/*}}}*//*{{{ Host/target common code */#define HOST#include "../tests/common.c"/*}}}*//*{{{ The test cases themselves *//*{{{ UsbTest definition */// ----------------------------------------------------------------------------// All the data associated with a single test.typedef struct UsbTest { // A "unique" identifier to make verbose output easier to understand. int id; // Which file descriptor should be used to access USB. int fd; // Which test should be run. usbtest which_test; // Test-specific details. union { UsbTest_Bulk bulk; UsbTest_ControlIn control_in; } test_params; // How to recover from any problems. Specifically, what kind of message // could the target send or receive that would unlock the thread on this // side. UsbTest_Recovery recovery; int result_pass; char result_message[USBTEST_MAX_MESSAGE]; unsigned char buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];} UsbTest;// Reset the information in a given test. This is used by the pool allocation// code. The data union is left alone, filling in the appropriate union// member is left to other code.static voidreset_usbtest(UsbTest* test){ static int next_id = 1; test->id = next_id++; test->which_test = usbtest_invalid; usbtest_recovery_reset(&(test->recovery)); test->result_pass = 0; test->result_message[0] = '\0';}/*}}}*//*{{{ bulk OUT */static voidrun_test_bulk_out(UsbTest* test){ unsigned char* buf = test->buffer; int i; VERBOSE(1, "Starting test %d, bulk OUT 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 packet_size = test->test_params.bulk.tx_size; test->recovery.endpoint = test->test_params.bulk.endpoint; test->recovery.protocol = USB_ENDPOINT_XFER_BULK; test->recovery.size = packet_size; usbtest_fill_buffer(&(test->test_params.bulk.data), buf, packet_size); if (verbose < 3) { VERBOSE(2, "Bulk OUT test %d: iteration %d, packet size %d\n", test->id, i, packet_size); } else { // Output the first 32 bytes of data as well. char msg[256]; int index; int j; index = snprintf(msg, 255, "Bulk OUT test %d: iteration %d, packet size %d\n Data %s:", test->id, i, packet_size, (usbtestdata_none == test->test_params.bulk.data.format) ? "(uninitialized)" : ""); for (j = 0; ((j + 3) < packet_size) && (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 < 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -