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

📄 usbhost.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    Tcl_GetInt(interp, argv[ 9], &(test->test_params.control_in.data.multiplier));    Tcl_GetInt(interp, argv[10], &(test->test_params.control_in.data.increment));    Tcl_GetInt(interp, argv[11], &(test->test_params.control_in.data.transfer_seed_multiplier));    Tcl_GetInt(interp, argv[12], &(test->test_params.control_in.data.transfer_seed_increment));    Tcl_GetInt(interp, argv[13], &(test->test_params.control_in.data.transfer_multiplier_multiplier));    Tcl_GetInt(interp, argv[14], &(test->test_params.control_in.data.transfer_multiplier_increment));    Tcl_GetInt(interp, argv[15], &(test->test_params.control_in.data.transfer_increment_multiplier));    Tcl_GetInt(interp, argv[16], &(test->test_params.control_in.data.transfer_increment_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_control_in(&(test->test_params.control_in), request, &request_index);    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_TEST_CONTROL_IN, 0, 0,                                 request_index, request);    remote_thread_count++;        return TCL_OK;}/*}}}*//*{{{  Cancel the current batch of tests                        */static inttcl_cancel(ClientData     clientData    __attribute__ ((unused)),           Tcl_Interp*    interp,           int            argc,           char**         argv          __attribute__ ((unused)) ){    if (1 != argc) {        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::cancel\"", TCL_STATIC);        return TCL_ERROR;    }    // Send the request on to the target.    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_CANCEL, 0, 0, 0, (void*)0);    // Now cancel all the local tests. This can be done by resetting the counter    // of allocated threads: no actual work will have been started yet.    local_thread_count = 0;    // And synchronise with the target    if (!usb_sync(usb_master_fd, 30)) {        fprintf(stderr, "usbhost: error, target has failed to process test cancel request.\n");        exit(EXIT_FAILURE);            }    remote_thread_count     = 0;        return TCL_OK;}/*}}}*//*{{{  Run a batch of tests                                     */// ----------------------------------------------------------------------------// This code does an awful lot of the hard work. Start with various utilities.// Has the current batch finished as far as the local threads are concerned?static intlocal_batch_finished(void){    int result = 1;    int i;    for (i = 0; i < local_thread_count; i++) {        if (pool[i].running) {            result = 0;            break;        }    }    return result;}// Has the current batch finished as far as remote threads are concerned?static intremote_batch_finished(void){    char buf[1];    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_FINISHED,                                 0, 0, 1, (void*) buf);    return buf[0];}// Perform recovery for a thread on the target. This involves asking the// target for recovery information, then performing an appropriate// action. If no data is returned then no recovery is needed for this thread.static voidrecover_remote(int index){    unsigned char       buffer[USBTEST_MAX_CONTROL_DATA];    int                 buffer_index;    UsbTest_Recovery    recovery;    int                 i;    if (0 != usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN,                                          USBTEST_GET_RECOVERY, 0, index, 12, buffer)) {        // There is work to be done        buffer_index = 0;        unpack_usbtest_recovery(&recovery, buffer, &buffer_index);        // We have an endpoint, a protocol, and a size.        if (0 == recovery.endpoint) {            // The target just needs a dummy reserved control message            usb_reliable_control_message(usb_master_fd, USB_TYPE_RESERVED | USB_RECIP_DEVICE, USBTEST_RESERVED_CONTROL_IN,                                         0, 0, 0, (void*) 0);        } else if (USB_ENDPOINT_XFER_BULK == recovery.protocol) {            // Either we need to send some data to the target, or we need to accept some data.            static unsigned char recovery_buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];                        struct  usbdevfs_bulktransfer    transfer;            transfer.ep         = recovery.endpoint;            transfer.timeout    = 2000; // Two seconds.  Should be plenty, even for a large bulk transfer.            transfer.data       = recovery_buffer;            if (USB_DIR_IN == (recovery.endpoint & USB_ENDPOINT_DIR_MASK)) {                transfer.len = recovery.size;            } else {                transfer.len = 1;            }            errno = 0;            i = ioctl(usb_master_fd, USBDEVFS_BULK, &transfer);        }        // There is no recovery support yet for other protocols.    }}// Perform recovery for a local thread. This involves extracting the// recovery information from the local thread and asking the target// to take appropriate action.static voidrecover_local(int index){    unsigned char   buffer[USBTEST_MAX_CONTROL_DATA];    int             buffer_index;    if (pool[index].running) {        buffer_index = 0;        pack_usbtest_recovery(&(pool[index].test.recovery), buffer, &buffer_index);        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_PERFORM_RECOVERY,                                     0, 0, buffer_index, (void*) buffer);    }}// All done, time for a clean-up on both target and host. The latter// is achieved simply by resetting the thread pool, which actually// just means resetting the counter since all the threads are blocked// waiting for the next batch.static voidrun_done(void){    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_BATCH_DONE, 0, 0, 0, (void*) NULL);    local_thread_count = 0;    remote_thread_count = 0;}// The main routine, as invoked from Tcl. This takes a single// argument, a timeout in seconds.static inttcl_run(ClientData     clientData    __attribute__ ((unused)),        Tcl_Interp*    interp,        int            argc,        char**         argv          __attribute__ ((unused)) ){    struct timespec delay;    int             timeout;    time_t          start;    time_t          now;    int             i, j;    unsigned char   result_buf[USBTEST_MAX_CONTROL_DATA];    int             all_ok;        if (2 != argc) {        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_run <timeout>\"", TCL_STATIC);        return TCL_ERROR;    }    if (TCL_OK != Tcl_GetInt(interp, argv[1], &timeout)) {        Tcl_SetResult(interp, "invalid argument: timeout should be numeric", TCL_STATIC);        return TCL_ERROR;    }        VERBOSE(2, "Starting a testrun, timeout %d seconds\n", timeout);        // Start the tests running on the target. The target USB hardware    // will not actually do anything except in response to packets    // from the host, so it is better to start the target before the    // local threads.    usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_START, 0, 0, 0, (void*) 0);    // Now the local threads can get going.    current_tests_terminated = 0;    pool_start();    // Now leave the various testing threads to do their thing until    // either side believes that the batch has finished, or until the    // timeout expires. Note that if one side decides that the batch    // has finished but the other disagrees, that in itself indicates    // a test failure of sorts.    //    // There is a question of polling frequency. Once a second avoids    // excessive polling traffic on the USB bus, and should not impose    // intolerable delays for short-duration tests.    start = time(NULL);    do {        VERBOSE(3, "The tests are running, waiting for termination\n");        delay.tv_sec    = 1;        delay.tv_nsec   = 0;        nanosleep(&delay, NULL);        now = time(NULL);    } while (((start + timeout) > now) && !local_batch_finished() && !remote_batch_finished());    VERBOSE(2, "Termination detected, time elapsed %ld\n", (long) now - start);    // If either side believes that testing is not complete, things    // get messy. Start by setting the terminated flag. Any tests that    // are actually still running happily but have not finished within    // the timeout should detect this and stop.    if (!local_batch_finished() || !remote_batch_finished()) {        VERBOSE(2, "Testing is not yet complete, setting TERMINATED flag\n");        current_tests_terminated    = 1;        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE, USBTEST_SET_TERMINATED, 0, 0, 0, (void*) 0);        // And another delay, to give threads a chance to detect the        // flag's update        delay.tv_sec    = 1;        delay.tv_nsec   = 0;        nanosleep(&delay, NULL);    }    // If there is still are unfinished threads, recovery action    // is needed. It is not clear whether it is better to unlock    // the local threads first, or the remote threads. For now the    // latter approach is taken.    if (!remote_batch_finished()) {        int i;        VERBOSE(2, "Remote threads still running, performing remote recovery\n");        for (i = 0; i < remote_thread_count; i++) {            recover_remote(i);        }        // Allow the recovery actions to take effect        delay.tv_sec    = 1;        delay.tv_nsec   = 0;        nanosleep(&delay, NULL);    }    if (!local_batch_finished()) {        int i;        VERBOSE(2, "Local threads still running, performing local recovery\n");        for (i = 0; i < local_thread_count; i++) {            recover_local(i);        }        // Allow the recovery actions to take effect        delay.tv_sec    = 1;        delay.tv_nsec   = 0;        nanosleep(&delay, NULL);    }    // One last check to make sure that everything is finished. If not,    // testing has broken down and it is necessary to abort.    if (!local_batch_finished() || !remote_batch_finished()) {        VERBOSE(2, "Giving local and remote threads another chance to finish.\n");        // Allow the recovery actions to take effect        delay.tv_sec    = 5;        delay.tv_nsec   = 0;        nanosleep(&delay, NULL);        if (!local_batch_finished() || !remote_batch_finished()) {            // OK, normality has not been restored.            // It would be nice to get hold of and display any error messages.            usb_abort(usb_master_fd);            fprintf(stderr, "Fatal error: the host test program and the remote target are out of synch.\n");            fprintf(stderr, "             recovery has been attempted, without success.\n");            fprintf(stderr, "             USB testing cannot continue.\n");            exit(EXIT_FAILURE);        }    }    VERBOSE(2, "Local and remote threads are in synch, collecting results.\n");        // The world is in a coherent state. Time to collect the results.    // The return value of this function is a simple boolean. More    // detailed results will be held in a Tcl variable as a list of    // messages. It is desirable to keep both local and remote results    // in order.    for (i = 0; i < ((local_thread_count < remote_thread_count) ? local_thread_count : remote_thread_count); i++) {        if (!pool[i].test.result_pass) {            Tcl_SetVar(interp, "usbtest::results", pool[i].test.result_message,                       all_ok ? (TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT) : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));            all_ok = 0;        }        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT,                                     0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf);        if (!result_buf[0]) {            Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]),                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));            all_ok = 0;        }    }    for (j = i; j < local_thread_count; j++) {        if (!pool[j].test.result_pass) {            Tcl_SetVar(interp, "usbtest::results", pool[j].test.result_message,                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));            all_ok = 0;        }    }    for (j = i; j < remote_thread_count; j++) {        usb_reliable_control_message(usb_master_fd, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, USBTEST_GET_RESULT,                                     0, i, USBTEST_MAX_CONTROL_DATA, (void*) result_buf);        if (!result_buf[0]) {            Tcl_SetVar(interp, "usbtest::results", &(result_buf[1]),                       all_ok ? TCL_GLOBAL_ONLY : (TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT));            all_ok = 0;        }    }    VERBOSE(2, "Overall test result %d

⌨️ 快捷键说明

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