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

📄 usbtarget.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
// that this update be undone. Also, the endpoint will have been locked to// detect concurrent tests on the control endpoint.static voidcancel_test_control_in(UsbTest* test){    CYG_ASSERTC(test == control_in_test);    control_in_test = (UsbTest*) 0;    control_in_test_packet_size = 0;    control_in_packets_transferred = 0;    unlock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN);    test->cancel_fn = (void (*)(UsbTest*)) 0;}// Prepare for a control-IN transfer test.static usbs_control_returnhandle_test_control_in(usb_devreq* req){    UsbTest*    test;    int         index   = 0;    CYG_ASSERTC((UsbTest*)0 == control_in_test);                    test = pool_allocate();    unpack_usbtest_control_in(&(test->test_params.control_in), class_request, &index);    lock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN);    test->which_test            = usbtest_control_in;    test->recovery.endpoint     = 0;    test->recovery.protocol     = USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL;    test->recovery.size         = 0;    // Does not actually matter    test->cancel_fn             = &cancel_test_control_in;    // Assume a pass. Failures are easy to detect.    test->result_pass   = 1;        control_in_test = test;    control_in_test_packet_size = test->test_params.control_in.packet_size_initial;    control_in_packets_transferred  = 0;    return USBS_CONTROL_RETURN_HANDLED;}    // The thread for a control-in test. Actually all the hard work is done at DSR// level, so this thread serves simply to detect when the test has completed// and to perform some clean-ups.static voidrun_test_control_in(UsbTest* test){    CYG_ASSERTC(test == control_in_test);        cyg_semaphore_wait(&(test->sem));    // The DSR has detected that the test is complete.    control_in_test = (UsbTest*) 0;    control_in_test_packet_size = 0;    control_in_packets_transferred = 0;    test->cancel_fn = (void (*)(UsbTest*)) 0;    unlock_endpoint(0, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN);}// ----------------------------------------------------------------------------// This is installed from inside main() as the handler for reserved// control messages.static usbs_control_returnhandle_reserved_control_messages(usbs_control_endpoint* endpoint, void* data){    usb_devreq*         req = (usb_devreq*) endpoint->control_buffer;    usbs_control_return result;    CYG_ASSERT(endpoint == control_endpoint, "control endpoint mismatch");    switch(req->request) {      case USBTEST_RESERVED_CONTROL_IN:        {            unsigned char*  buf;            int             len;                        if ((UsbTest*)0 == control_in_test) {                result = USBS_CONTROL_RETURN_STALL;                break;            }            // Is this test over? If so indicate a failure because we            // cannot have received all the control packets.            if (current_tests_terminated) {                control_in_test->result_pass   = 0;                snprintf(control_in_test->result_message, USBTEST_MAX_MESSAGE,                         "Target, control IN transfer: not all packets received.");                cyg_semaphore_post(&(control_in_test->sem));                control_in_test = (UsbTest*) 0;                result = USBS_CONTROL_RETURN_STALL;                break;            }                        // A control-IN test is indeed in progress, and the current state is            // held in control_in_test and control_in_test_packet_size. Check that            // the packet size matches up, i.e. that host and target are in sync.            len = (req->length_hi << 8) || req->length_lo;            if (control_in_test_packet_size != len) {                control_in_test->result_pass   = 0;                snprintf(control_in_test->result_message, USBTEST_MAX_MESSAGE,                         "Target, control IN transfer on endpoint %d : the host only requested %d bytes instead of %d",                         len, control_in_test_packet_size);                cyg_semaphore_post(&(control_in_test->sem));                control_in_test = (UsbTest*) 0;                result = USBS_CONTROL_RETURN_STALL;                break;            }            // Prepare a suitable reply buffer. This is happening at            // DSR level so runtime is important, but with an upper            // bound of 255 bytes the buffer should be small enough.            buf = control_in_test->buffer;            usbtest_fill_buffer(&(control_in_test->test_params.control_in.data), buf, control_in_test_packet_size);            control_endpoint->buffer_size   = control_in_test_packet_size;            control_endpoint->buffer        = buf;            USBTEST_CONTROL_NEXT_PACKET_SIZE(control_in_test_packet_size, control_in_test->test_params.control_in);            // Have all the packets been transferred?            control_in_packets_transferred++;            if (control_in_packets_transferred == control_in_test->test_params.control_in.number_packets) {                cyg_semaphore_post(&(control_in_test->sem));                control_in_test = (UsbTest*) 0;            }            result = USBS_CONTROL_RETURN_HANDLED;            break;      }      default:        CYG_FAIL("Unexpected reserved control message");        break;    }        return result;}/*}}}*/// FIXME: add more tests.// 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 voidrun_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:        CYG_TEST_FAIL_EXIT("Internal error, attempt to run unknown test.\n");        break;    }}/*}}}*//*{{{  The thread pool                                          */// ----------------------------------------------------------------------------// Just like on the host side, it is desirable to have a pool of// threads available to perform test operations. Strictly speaking// some tests will run without needing a separate thread, since many// operations can be performed at DSR level. However typical// application code will involve threads and it is desirable for test// code to behave the same way. Also, some operations like validating// the transferred data are expensive, and best done in thread context.typedef struct PoolEntry {    cyg_sem_t           wakeup;    cyg_thread          thread_data;    cyg_handle_t        thread_handle;    char                thread_name[16];    char                thread_stack[2 * CYGNUM_HAL_STACK_SIZE_TYPICAL];    cyg_bool            in_use;    cyg_bool            running;    UsbTest             test;} PoolEntry;// This array must be uninitialized, or the executable size would// be ludicrous.PoolEntry  pool[USBTEST_MAX_CONCURRENT_TESTS];// The entry point for every thread in the pool. It just loops forever,// waiting until it is supposed to run a test.static voidpool_thread_function(cyg_addrword_t arg){    PoolEntry*  pool_entry  = (PoolEntry*) arg;    for ( ; ; ) {        cyg_semaphore_wait(&(pool_entry->wakeup));        run_test(&(pool_entry->test));        pool_entry->running = 0;    }}// Initialize all threads in the pool.static voidpool_initialize(void){    int i;    for (i = 0; i < USBTEST_MAX_CONCURRENT_TESTS; i++) {        cyg_semaphore_init(&(pool[i].wakeup), 0);        pool[i].in_use  = 0;        pool[i].running = 0;        sprintf(pool[i].thread_name, "worker%d", i);        cyg_thread_create( 0, &pool_thread_function, (cyg_addrword_t) &(pool[i]),                           pool[i].thread_name, pool[i].thread_stack, 2 * CYGNUM_HAL_STACK_SIZE_TYPICAL,                           &(pool[i].thread_handle), &(pool[i].thread_data));        cyg_thread_resume(pool[i].thread_handle);    }}// Allocate a single entry in the thread poolstatic UsbTest*pool_allocate(void){    UsbTest*    result  = (UsbTest*) 0;    if (thread_counter == USBTEST_MAX_CONCURRENT_TESTS) {        CYG_TEST_FAIL_EXIT("Internal error, thread resources exhaused.\n");    }        result = &(pool[thread_counter].test);    thread_counter++;    reset_usbtest(result);    return result;}// Start all the threads that are supposed to be running tests.static voidpool_start(void){    int i;    for (i = 0; i < thread_counter; i++) {        pool[i].running = 1;        cyg_semaphore_post(&(pool[i].wakeup));    }}/*}}}*//*{{{  Class control messages                                   */// ----------------------------------------------------------------------------// Handle class control messages. These provide the primary form of// communication between host and target. There are requests to find out// the number of endpoints, details of each endpoint, prepare a test run,// abort a test run, get status, terminate the target-side, and so on.// The handlers for starting specific test cases are kept alongside// the test cases themselves.//// Note that these handlers will typically be invoked from DSR context// and hence they are subject to the usual DSR restrictions.//// Problems have been experienced in some hosts sending control messages// that involve additional host->target data. An ugly workaround is// in place whereby any such data is sent in advance using separate// control messages./*{{{  endpoint count                                           */// How many endpoints are supported by this device? That information is// determined during initialization.static usbs_control_returnhandle_endpoint_count(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));        class_reply[0]                  = (unsigned char) number_endpoints;    control_endpoint->buffer        = class_reply;    control_endpoint->buffer_size   = 1;    return USBS_CONTROL_RETURN_HANDLED;}/*}}}*//*{{{  endpoint details                                         */// The host wants to know the details of a specific USB endpoint.// The format is specified in protocol.hstatic usbs_control_returnhandle_endpoint_details(usb_devreq* req){    int buf_index;    CYG_ASSERTC((req->type & USB_DEVREQ_DIRECTION_MASK) == USB_DEVREQ_DIRECTION_IN);    CYG_ASSERTC((USBTEST_MAX_CONTROL_DATA == req->length_lo) && (0 == req->length_hi));    CYG_ASSERTC(req->index_lo < number_endpoints);    CYG_ASSERTC((0 == req->index_hi) && (0 == req->value_lo) && (0 == req->value_hi));        class_reply[0]  = (unsigned char) usbs_testing_endpoints[req->index_lo].endpoint_type;    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

⌨️ 快捷键说明

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