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

📄 usbtarget.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
    class_reply[1]  = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_number;
    class_reply[2]  = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_direction;
    class_reply[3]  = (unsigned char) usbs_testing_endpoints[req->index_lo].max_in_padding;
    buf_index = 4;
    pack_int(usbs_testing_endpoints[req->index_lo].min_size, class_reply, &buf_index);
    pack_int(usbs_testing_endpoints[req->index_lo].max_size, class_reply, &buf_index);
    if (NULL == usbs_testing_endpoints[req->index_lo].devtab_entry) {
        class_reply[buf_index]    = '\0';
        control_endpoint->buffer_size   = buf_index + 1;
    } else {
        int len = strlen(usbs_testing_endpoints[req->index_lo].devtab_entry) + buf_index + 1;
        if (len > USBTEST_MAX_CONTROL_DATA) {
            return USBS_CONTROL_RETURN_STALL;
        } else {
            strcpy(&(class_reply[buf_index]), usbs_testing_endpoints[req->index_lo].devtab_entry);
            control_endpoint->buffer_size   = len;
        }
    }
    control_endpoint->buffer        = class_reply;
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  sync                                                     */

// The host wants to know whether or not the target is currently busy doing
// stuff. This information is held in a static.
static usbs_control_return
handle_sync(usb_devreq* req)
{
    CYG_ASSERTC((1 == req->length_lo) && (0 == req->length_hi) && \
                ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A sync operation should not involve any data");
    
    class_reply[0]                  = (unsigned char) idle;
    control_endpoint->buffer        = class_reply;
    control_endpoint->buffer_size   = 1;
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  pass/fail                                                */

// Allow the host to generate some pass or fail messages, and
// optionally terminate the test. These are synchronous requests
// so the data can be left in class_request.

static int passfail_request   = 0;

// Invoked from thread context
static void
handle_passfail_action(void)
{
    switch (passfail_request) {
      case USBTEST_PASS:
        CYG_TEST_PASS(class_request);
        break;
      case USBTEST_PASS_EXIT:
        CYG_TEST_PASS(class_request);
        CYG_TEST_EXIT("Exiting normally as requested by the host");
        break;
      case USBTEST_FAIL:
        CYG_TEST_FAIL(class_request);
        break;
      case USBTEST_FAIL_EXIT:
        CYG_TEST_FAIL(class_request);
        CYG_TEST_EXIT("Exiting normally as requested by the host");
        break;
      default:
        CYG_FAIL("Bogus invocation of usbtest_main_passfail");
        break;
    }
}

// Invoked from DSR context
static usbs_control_return
handle_passfail(usb_devreq* req)
{
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(class_request_size > 0, "A pass/fail message should be supplied");
    CYG_ASSERT(idle, "Pass/fail messages are only allowed when idle");
    CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending.");
    
    passfail_request    = req->request;
    idle                = false;
    main_thread_action  = &handle_passfail_action;
    cyg_semaphore_post(&main_wakeup);

    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  abort                                                    */

// The host has concluded that there is no easy way to get both target and
// host back to a sensible state. For example there may be a thread that
// is blocked waiting for some I/O that is not going to complete. The abort
// should be handled at thread level, not DSR level, so that the host
// still sees the low-level USB handshake.

static void
handle_abort_action(void)
{
    CYG_TEST_FAIL_EXIT("Test abort requested by host application");
}

static usbs_control_return
handle_abort(usb_devreq* req)
{
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(idle, "Abort messages are only allowed when idle");
    CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending.");
    
    idle                = false;
    main_thread_action  = &handle_abort_action;
    cyg_semaphore_post(&main_wakeup);
    
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  cancel                                                   */

// Invoked from thread context
// Cancelling pending test cases simply involves iterating over the allocated
// entries in the pool, invoking any cancellation functions that have been
// defined, and then resetting the tread count. The actual tests have not
// yet started so none of the threads will be active.
static void
handle_cancel_action(void)
{
    int i;
    for (i = 0; i < thread_counter; i++) {
        if ((void (*)(UsbTest*))0 != pool[i].test.cancel_fn) {
            (*(pool[i].test.cancel_fn))(&(pool[i].test));
            pool[i].test.cancel_fn  = (void (*)(UsbTest*)) 0;
        }
    }
    thread_counter    = 0;
}

// Invoked from DSR context
static usbs_control_return
handle_cancel(usb_devreq* req)
{
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A cancel operation should not involve any data");
    CYG_ASSERT(idle, "Cancel requests are only allowed when idle");
    CYG_ASSERT(!running, "Cancel requests cannot be sent once the system is running");
    CYG_ASSERT((void (*)(void))0 == main_thread_action, "No thread operation should be pending.");
    
    idle                = false;
    main_thread_action = &handle_cancel_action;
    cyg_semaphore_post(&main_wakeup);

    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  start                                                    */

// Start the tests running. This just involves waking up the pool threads
// and setting the running flag, with the latter serving primarily for
// assertions. 

static usbs_control_return
handle_start(usb_devreq* req)
{
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A start operation should not involve any data");
    CYG_ASSERT(!running, "Start requests cannot be sent if the system is already running");

    current_tests_terminated = false;
    running = true;
    pool_start();
    
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  finished                                                 */

// Have all the tests finished? This involves checking all the threads
// involved in the current batch of tests and seeing whether or not
// their running flag is still set.

static usbs_control_return
handle_finished(usb_devreq* req)
{
    int i;
    int result = 1;
    
    CYG_ASSERTC((1 == req->length_lo) && (0 == req->length_hi) && \
                ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A finished operation should not involve any data");
    CYG_ASSERT(running, "Finished requests can only be sent if the system is already running");
    
    for (i = 0; i < thread_counter; i++) {
        if (pool[i].running) {
            result = 0;
            break;
        }
    }
    class_reply[0]                  = (unsigned char) result;
    control_endpoint->buffer        = class_reply;
    control_endpoint->buffer_size   = 1;
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  set terminated                                           */

// A timeout has occurred, or there is some other failure. The first step
// in recovery is to set the terminated flag so that as recovery action
// takes place and the threads wake up they make no attempt to continue
// doing more transfers.

static usbs_control_return
handle_set_terminated(usb_devreq* req)
{
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A set-terminated operation should not involve any data");
    CYG_ASSERT(running, "The terminated flag can only be set when there are running tests");

    current_tests_terminated = 1;
    
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  get recovery                                             */

// Return the recovery information for one of the threads involved in the
// current batch of tests, so that the host can perform a USB operation
// that will sort out that thread.
static usbs_control_return
handle_get_recovery(usb_devreq* req)
{
    int buffer_index;
    
    CYG_ASSERT(current_tests_terminated, "Recovery should only be attempted when the terminated flag is set");
    CYG_ASSERT(running, "If there are no tests running then recovery is impossible");
    CYG_ASSERTC((12 == req->length_lo) && (0 == req->length_hi) && \
                ((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN));
    CYG_ASSERTC(req->index_lo <= thread_counter);
    CYG_ASSERTC((0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(0 == class_request_size, "A get-recovery operation should not involve any data");

    control_endpoint->buffer        = class_reply;
    if (!pool[req->index_lo].running) {
        // Actually, this particular thread has terminated so no recovery is needed.
        control_endpoint->buffer_size   = 0;
    } else {
        buffer_index    = 0;
        pack_usbtest_recovery(&(pool[req->index_lo].test.recovery), class_reply, &buffer_index);
        control_endpoint->buffer_size   = buffer_index;
    }
    
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  perform recovery                                         */

// The host has identified a course of action that could unlock a thread
// on the host-side that is currently blocked performing a USB operation.
// Typically this involves either sending or accepting some data. If the
// endpoint is still locked, in other words if there is a still a local
// thread attempting to communicate on the specified endpoint, then
// things are messed up: both sides are trying to communicate, but nothing
// is happening. The eCos USB API is such that attempting multiple
// concurrent operations on a single endpoint is disallowed, so
// the recovery request has to be ignored. If things do not sort themselves
// out then the whole test run will have to be aborted.

// A dummy completion function for when a recovery operation has completed.
static void
recovery_callback(void* callback_arg, int transferred)
{
    CYG_UNUSED_PARAM(void*, callback_arg);
    CYG_UNUSED_PARAM(int, transferred);
}
    
static usbs_control_return
handle_perform_recovery(usb_devreq* req)
{
    int                 buffer_index;
    int                 endpoint_number;
    int                 endpoint_direction;
    UsbTest_Recovery    recovery;
    
    CYG_ASSERT(current_tests_terminated, "Recovery should only be attempted when the terminated flag is set");
    CYG_ASSERT(running, "If there are no tests running then recovery is impossible");
    CYG_ASSERTC((0 == req->length_lo) && (0 == req->length_hi));
    CYG_ASSERTC((0 == req->index_lo) && (0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));
    CYG_ASSERT(12 == class_request_size, "A perform-recovery operation requires recovery data");

    buffer_index = 0;
    unpack_usbtest_recovery(&recovery, class_request, &buffer_index);
    endpoint_number     = recovery.endpoint & ~USB_DEVREQ_DIRECTION_MASK;
    endpoint_direction  = recovery.endpo

⌨️ 快捷键说明

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