⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbhost.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
                                  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 + -