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

📄 usbhost.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
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;
    int ret;
    
    for ( ; ; ) {
        do {
             ret = sem_wait(&(pool_entry->wakeup));
             if (ret != 0 && errno != EINTR) {
                  perror("sem_wait");
                  exit(1);
             }
        } while (ret != 0);
        run_test(&(pool_entry->test));
        pool_entry->running = 0;
    }

    return NULL;
}

// Initialize all threads in the pool.
static void
pool_initialize(void)
{
    int i;
    for (i = 0; i < USBTEST_MAX_CONCURRENT_TESTS; i++) {
        pool[i].running = 0;
        pool[i].test.fd = dup(usb_master_fd);
        if (0 != sem_init(&(pool[i].wakeup), 0, 0)) {
            fprintf(stderr, "usbhost: internal error, failed to initialize all semaphores.\n");
            exit(EXIT_FAILURE);
        }
        if (0 != pthread_create(&(pool[i].thread), NULL, &pool_function, (void*) &(pool[i]))) {
            fprintf(stderr, "usbhost: internal error, failed to start all threads.\n");
            exit(EXIT_FAILURE);
        }
    }
}

// Allocate a single entry in the thread pool.
static UsbTest*
pool_allocate(void)
{
    UsbTest* result = (UsbTest*) 0;

    if (local_thread_count == USBTEST_MAX_CONCURRENT_TESTS) {
        fprintf(stderr, "usbhost: internal error, thread resource exhausted.\n");
        exit(EXIT_FAILURE);
    }

    result = &(pool[local_thread_count].test);
    local_thread_count++;
    reset_usbtest(result);
    return result;
}

// Start all the threads that are supposed to be running tests.
static void
pool_start(void)
{
    int i;
    for (i = 0; i < local_thread_count; i++) {
        pool[i].running = 1;
        sem_post(&(pool[i].wakeup));
    }
}

/*}}}*/
/*{{{  Tcl routines                                             */

// ----------------------------------------------------------------------------
// Tcl routines to provide access to the USB device from inside Tcl
// scripts, plus some general utilities. These routines deal mostly
// with preparing a test run. The actual work is done in C: the
// ioctl() operations are not readily accessible from Tcl, and
// operations like filling in buffers and calculating checksums are
// cpu-intensive.

/*{{{  pass/fail/abort                                          */

// ----------------------------------------------------------------------------
// Some simple routines accessible from Tcl to get the target to report pass/fail or
// to make the target abort.

static int
tcl_target_pass(ClientData     clientData  __attribute__ ((unused)),
                Tcl_Interp*    interp,
                int            argc,
                char**         argv)
{
    if (2 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass <message>\"", TCL_STATIC);
        return TCL_ERROR;
    }
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS, 0, 0, strlen(argv[1]) + 1, argv[1]);
    usb_sync(usb_master_fd, -1);
    return TCL_OK;
}

static int
tcl_target_fail(ClientData     clientData  __attribute__ ((unused)),
                Tcl_Interp*    interp,
                int            argc,
                char**         argv)
{
    if (2 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail <message>\"", TCL_STATIC);
        return TCL_ERROR;
    }
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL, 0, 0, strlen(argv[1]) + 1, argv[1]);
    usb_sync(usb_master_fd, -1);
    return TCL_OK;
}

// The next three routines cause the target to exit, so a usb_sync() is inappropriate.
static int
tcl_target_pass_exit(ClientData     clientData  __attribute__ ((unused)),
                     Tcl_Interp*    interp,
                     int            argc,
                     char**         argv)
{
    if (2 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_pass_exit <message>\"", TCL_STATIC);
        return TCL_ERROR;
    }
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PASS_EXIT, 0, 0,
                                 strlen(argv[1]) + 1, argv[1]);
    return TCL_OK;
}


static int
tcl_target_fail_exit(ClientData     clientData  __attribute__ ((unused)),
                     Tcl_Interp*    interp,
                     int            argc,
                     char**         argv)
{
    if (2 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_fail_exit <message>\"", TCL_STATIC);
        return TCL_ERROR;
    }
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_FAIL_EXIT, 0, 0,
                                 strlen(argv[1]) + 1, argv[1]);
    return TCL_OK;
}

static int
tcl_target_abort(ClientData     clientData  __attribute__ ((unused)),
                 Tcl_Interp*    interp,
                 int            argc,
                 char**         argv        __attribute__ ((unused)) )
{
    if (1 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::target_abort\"", TCL_STATIC);
        return TCL_ERROR;
    }
    usb_abort(usb_master_fd);
    return TCL_OK;
}

/*}}}*/
/*{{{  start bulk test                                          */

// ----------------------------------------------------------------------------
// Start a bulk test. The real Tcl interface to this functionality is
// implemented in Tcl: it takes care of figuring out sensible default
// arguments, validating the data, etc. All that this code does is
// allocate a thread and fill in the appropriate data, plus request
// the target-side to do the same thing.

static int
tcl_test_bulk(ClientData     clientData  __attribute__ ((unused)),
              Tcl_Interp*    interp,
              int            argc,
              char**         argv)
{
    int             i;
    int             tmp;
    UsbTest*        test;
    unsigned char   request[USBTEST_MAX_CONTROL_DATA];
    int             request_index;

    // The data consists of 28 numbers for UsbTest_Bulk itself, and
    // another 10 numbers for the test data definition.
    if (39 != argc) {
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_test_bulk <message>\"", TCL_STATIC);
        return TCL_ERROR;
    }
    for (i = 1; i < 39; i++) {
        int discard;
        if (TCL_OK != Tcl_GetInt(interp, argv[i], &discard)) {
            Tcl_SetResult(interp, "invalid argument: all arguments should be numbers", TCL_STATIC);
            return TCL_ERROR;
        }
    }

    test = pool_allocate();
    Tcl_GetInt(interp, argv[1], &(test->test_params.bulk.number_packets));
    Tcl_GetInt(interp, argv[2], &(test->test_params.bulk.endpoint));
    test->which_test = (USB_DIR_IN == (test->test_params.bulk.endpoint & USB_ENDPOINT_DIR_MASK))
        ? usbtest_bulk_in : usbtest_bulk_out;
    Tcl_GetInt(interp, argv[ 3], &(test->test_params.bulk.tx_size));
    Tcl_GetInt(interp, argv[ 4], &(test->test_params.bulk.tx_size_min));
    Tcl_GetInt(interp, argv[ 5], &(test->test_params.bulk.tx_size_max));
    Tcl_GetInt(interp, argv[ 6], &(test->test_params.bulk.tx_size_multiplier));
    Tcl_GetInt(interp, argv[ 7], &(test->test_params.bulk.tx_size_divisor));
    Tcl_GetInt(interp, argv[ 8], &(test->test_params.bulk.tx_size_increment));
    Tcl_GetInt(interp, argv[ 9], &(test->test_params.bulk.rx_size));
    Tcl_GetInt(interp, argv[10], &(test->test_params.bulk.rx_size_min));
    Tcl_GetInt(interp, argv[11], &(test->test_params.bulk.rx_size_max));
    Tcl_GetInt(interp, argv[12], &(test->test_params.bulk.rx_size_multiplier));
    Tcl_GetInt(interp, argv[13], &(test->test_params.bulk.rx_size_divisor));
    Tcl_GetInt(interp, argv[14], &(test->test_params.bulk.rx_size_increment));
    Tcl_GetInt(interp, argv[15], &(test->test_params.bulk.rx_padding));
    Tcl_GetInt(interp, argv[16], &(test->test_params.bulk.tx_delay));
    Tcl_GetInt(interp, argv[17], &(test->test_params.bulk.tx_delay_min));
    Tcl_GetInt(interp, argv[18], &(test->test_params.bulk.tx_delay_max));
    Tcl_GetInt(interp, argv[19], &(test->test_params.bulk.tx_delay_multiplier));
    Tcl_GetInt(interp, argv[20], &(test->test_params.bulk.tx_delay_divisor));
    Tcl_GetInt(interp, argv[21], &(test->test_params.bulk.tx_delay_increment));
    Tcl_GetInt(interp, argv[22], &(test->test_params.bulk.rx_delay));
    Tcl_GetInt(interp, argv[23], &(test->test_params.bulk.rx_delay_min));
    Tcl_GetInt(interp, argv[24], &(test->test_params.bulk.rx_delay_max));
    Tcl_GetInt(interp, argv[25], &(test->test_params.bulk.rx_delay_multiplier));
    Tcl_GetInt(interp, argv[26], &(test->test_params.bulk.rx_delay_divisor));
    Tcl_GetInt(interp, argv[27], &(test->test_params.bulk.rx_delay_increment));
    Tcl_GetInt(interp, argv[28], &tmp);
    test->test_params.bulk.io_mechanism = (usb_io_mechanism) tmp;
    Tcl_GetInt(interp, argv[29], &tmp);
    test->test_params.bulk.data.format = (usbtestdata) tmp;
    Tcl_GetInt(interp, argv[30], &(test->test_params.bulk.data.seed));
    Tcl_GetInt(interp, argv[31], &(test->test_params.bulk.data.multiplier));
    Tcl_GetInt(interp, argv[32], &(test->test_params.bulk.data.increment));
    Tcl_GetInt(interp, argv[33], &(test->test_params.bulk.data.transfer_seed_multiplier));
    Tcl_GetInt(interp, argv[34], &(test->test_params.bulk.data.transfer_seed_increment));
    Tcl_GetInt(interp, argv[35], &(test->test_params.bulk.data.transfer_multiplier_multiplier));
    Tcl_GetInt(interp, argv[36], &(test->test_params.bulk.data.transfer_multiplier_increment));
    Tcl_GetInt(interp, argv[37], &(test->test_params.bulk.data.transfer_increment_multiplier));
    Tcl_GetInt(interp, argv[38], &(test->test_params.bulk.data.transfer_increment_increment));

    VERBOSE(3, "Preparing USB bulk test on endpoint %d, direction %s, for %d packets\n", \
            test->test_params.bulk.endpoint, \
            (usbtest_bulk_in == test->which_test) ? "IN" : "OUT", \
            test->test_params.bulk.number_packets);
    VERBOSE(3, "  I/O mechanism is %s\n", \
            (usb_io_mechanism_usb == test->test_params.bulk.io_mechanism) ? "low-level USB" : \
            (usb_io_mechanism_dev == test->test_params.bulk.io_mechanism) ? "devtab" : "<invalid>");
    VERBOSE(3, "  Data format %s, data1 %d, data* %d, data+ %d, data1* %d, data1+ %d, data** %d, data*+ %d, data+* %d, data++ %d\n",\
            (usbtestdata_none     == test->test_params.bulk.data.format) ? "none" :     \
            (usbtestdata_bytefill == test->test_params.bulk.data.format) ? "bytefill" : \
            (usbtestdata_wordfill == test->test_params.bulk.data.format) ? "wordfill" : \
            (usbtestdata_byteseq  == test->test_params.bulk.data.format) ? "byteseq"  : \
            (usbtestdata_wordseq  == test->test_params.bulk.data.format) ? "wordseq"  : "<invalid>", \
            test->test_params.bulk.data.seed,                            \
            test->test_params.bulk.data.multiplier,                      \
            test->test_params.bulk.data.increment,                       \
            test->test_params.bulk.data.transfer_seed_multiplier,        \
            test->test_params.bulk.data.transfer_seed_increment,         \
            test->test_params.bulk.data.transfer_multiplier_multiplier,  \
            test->test_params.bulk.data.transfer_multiplier_increment,   \
            test->test_params.bulk.data.transfer_increment_multiplier,   \
            test->test_params.bulk.data.transfer_increment_increment);
    VERBOSE(3, "  txsize1 %d, txsize>= %d, txsize<= %d, txsize* %d, txsize/ %d, txsize+ %d\n", \
            test->test_params.bulk.tx_size,         test->test_params.bulk.tx_size_min,        \
            test->test_params.bulk.tx_size_max,     test->test_params.bulk.tx_size_multiplier, \
            test->test_params.bulk.tx_size_divisor, test->test_params.bulk.tx_size_increment);
    VERBOSE(3, "  rxsize1 %d, rxsize>= %d, rxsize<= %d, rxsize* %d, rxsize/ %d, rxsize+ %d\n", \
            test->test_params.bulk.rx_size,         test->test_params.bulk.rx_size_min,        \
            test->test_params.bulk.rx_size_max,     test->test_params.bulk.rx_size_multiplier, \
            test->test_params.bulk.rx_size_divisor, test->test_params.bulk.rx_size_increment);
    VERBOSE(3, "  txdelay1 %d, txdelay>= %d, txdelay<= %d, txdelay* %d, txdelay/ %d, txdelay+ %d\n", \
            test->test_params.bulk.tx_delay,         test->test_params.bulk.tx_delay_min,            \
            test->test_params.bulk.tx_delay_max,     test->test_params.bulk.tx_delay_multiplier,     \
            test->test_params.bulk.tx_delay_divisor, test->test_params.bulk.tx_delay_increment);
    VERBOSE(3, "  rxdelay1 %d, rxdelay>= %d, rxdelay<= %d, rxdelay* %d, rxdelay/ %d, rxdelay+ %d\n", \
            test->test_params.bulk.rx_delay,         test->test_params.bulk.rx_delay_min,            \
            test->test_params.bulk.rx_delay_max,     test->test_params.bulk.rx_delay_multiplier,     \
            test->test_params.bulk.rx_delay_divisor, test->test_params.bulk.rx_delay_increment);
            
    
    // That is all the data converted from Tcl to C, and a local thread is set up to handle this
    // request. Also set up a thread on the target.
    request_index = 0;
    pack_usbtest_bulk(&(test->test_params.bulk), request, &request_index);
    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_BULK, 0, 0, request_index, request);
    remote_thread_count++;
    
    return TCL_OK;
}

/*}}}*/
/*{{{  start control-in test                                    */

// ----------------------------------------------------------------------------
// Start a control-in test. The real Tcl interface to this
// functionality is implemented in Tcl: it takes care of figuring out
// sensible default arguments, validating the data, etc. All that this

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -