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

📄 usbtarget.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
        if ((usbs_testing_endpoints[i].endpoint_type        == protocol)        &&
            (usbs_testing_endpoints[i].endpoint_number      == endpoint_number) &&
            (usbs_testing_endpoints[i].endpoint_direction   == direction)) {
            result = i;
            break;
        }
    }
    return result;
}

/*}}}*/
/*{{{  Enumeration data                                         */

// ----------------------------------------------------------------------------
// The enumeration data.
//
// For simplicity this configuration involves just a single interface.
// The target has to list all the endpoints, or the Linux kernel will
// not allow application code to access them. Hence the information
// provided by the device drivers has to be turned into endpoint descriptors.

usb_configuration_descriptor usb_configuration = {
    length:             USB_CONFIGURATION_DESCRIPTOR_LENGTH,
    type:               USB_CONFIGURATION_DESCRIPTOR_TYPE,
    total_length_lo:    USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(1, 0),
    total_length_hi:    USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, 0),
    number_interfaces:  1,
    configuration_id:   1,      // id 0 is special according to the spec
    configuration_str:  0,
    attributes:         USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED |
                        USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED,
    max_power:          50
};

usb_interface_descriptor usb_interface = {
    length:             USB_INTERFACE_DESCRIPTOR_LENGTH,
    type:               USB_INTERFACE_DESCRIPTOR_TYPE,
    interface_id:       0,
    alternate_setting:  0,
    number_endpoints:   0,
    interface_class:    USB_INTERFACE_DESCRIPTOR_CLASS_VENDOR,
    interface_subclass: USB_INTERFACE_DESCRIPTOR_SUBCLASS_VENDOR,
    interface_protocol: USB_INTERFACE_DESCRIPTOR_PROTOCOL_VENDOR,
    interface_str:      0
};

usb_endpoint_descriptor usb_endpoints[USBTEST_MAX_ENDPOINTS];
                               
const unsigned char* usb_strings[] = {
    "\004\003\011\004",
    "\020\003R\000e\000d\000 \000H\000a\000t\000",
    "\054\003R\000e\000d\000 \000H\000a\000t\000 \000e\000C\000o\000s\000 \000"
    "U\000S\000B\000 \000t\000e\000s\000t\000"
};

usbs_enumeration_data usb_enum_data = {
    {
        length:                 USB_DEVICE_DESCRIPTOR_LENGTH,
        type:                   USB_DEVICE_DESCRIPTOR_TYPE,
        usb_spec_lo:            USB_DEVICE_DESCRIPTOR_USB11_LO,
        usb_spec_hi:            USB_DEVICE_DESCRIPTOR_USB11_HI,
        device_class:           USB_DEVICE_DESCRIPTOR_CLASS_VENDOR,
        device_subclass:        USB_DEVICE_DESCRIPTOR_SUBCLASS_VENDOR,
        device_protocol:        USB_DEVICE_DESCRIPTOR_PROTOCOL_VENDOR,
        max_packet_size:        8,
        vendor_lo:              0x42,   // Note: this is not an allocated vendor id
        vendor_hi:              0x42,
        product_lo:             0x00,
        product_hi:             0x01,
        device_lo:              0x00,
        device_hi:              0x01,
        manufacturer_str:       1,
        product_str:            2,
        serial_number_str:      0,
        number_configurations:  1
    },
    total_number_interfaces:    1,
    total_number_endpoints:     0,
    total_number_strings:       3,
    configurations:             &usb_configuration,
    interfaces:                 &usb_interface,
    endpoints:                  usb_endpoints,
    strings:                    usb_strings
};

static void
provide_endpoint_enumeration_data(void)
{
    int enum_endpoint_count = 0;
    int i;

    for (i = 0; !USBS_TESTING_ENDPOINTS_IS_TERMINATOR(usbs_testing_endpoints[i]); i++) {

        // The control endpoint need not appear in the enumeration data.
        if (USB_ENDPOINT_DESCRIPTOR_ATTR_CONTROL == usbs_testing_endpoints[i].endpoint_type) {
            continue;
        }

        usb_endpoints[enum_endpoint_count].length          = USB_ENDPOINT_DESCRIPTOR_LENGTH;
        usb_endpoints[enum_endpoint_count].type            = USB_ENDPOINT_DESCRIPTOR_TYPE;
        usb_endpoints[enum_endpoint_count].endpoint        = usbs_testing_endpoints[i].endpoint_number |
                                                             usbs_testing_endpoints[i].endpoint_direction;

        switch (usbs_testing_endpoints[i].endpoint_type) {
          case USB_ENDPOINT_DESCRIPTOR_ATTR_BULK:
            usb_endpoints[enum_endpoint_count].attributes      = USB_ENDPOINT_DESCRIPTOR_ATTR_BULK;
            usb_endpoints[enum_endpoint_count].max_packet_lo   = 64;
            usb_endpoints[enum_endpoint_count].max_packet_hi   = 0;
            usb_endpoints[enum_endpoint_count].interval        = 0;
            break;
            
          case USB_ENDPOINT_DESCRIPTOR_ATTR_ISOCHRONOUS:
            usb_endpoints[enum_endpoint_count].attributes      = USB_ENDPOINT_DESCRIPTOR_ATTR_ISOCHRONOUS;
            usb_endpoints[enum_endpoint_count].max_packet_lo   = usbs_testing_endpoints[i].max_size & 0x0FF;
            usb_endpoints[enum_endpoint_count].max_packet_hi   = (usbs_testing_endpoints[i].max_size >> 8) & 0x0FF;
            usb_endpoints[enum_endpoint_count].interval        = 1;
            break;
            
          case USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT:
            usb_endpoints[enum_endpoint_count].attributes      = USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT;
            usb_endpoints[enum_endpoint_count].max_packet_lo   = (unsigned char) usbs_testing_endpoints[i].max_size;
            usb_endpoints[enum_endpoint_count].max_packet_hi   = 0;
            usb_endpoints[enum_endpoint_count].interval        = 1;    // NOTE: possibly incorrect
            break;
        }

        enum_endpoint_count++;
    }

    usb_interface.number_endpoints          = enum_endpoint_count;
    usb_enum_data.total_number_endpoints    = enum_endpoint_count;
    usb_configuration.total_length_lo       = USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(1, enum_endpoint_count);
    usb_configuration.total_length_hi       = USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(1, enum_endpoint_count);
}

/*}}}*/
/*{{{  Host/target common code                                  */

#define TARGET
#include "common.c"

/*}}}*/
/*{{{  The tests                                                */

/*{{{  UsbTest structure                                        */

// ----------------------------------------------------------------------------
// All the information associated with a particular testcase. Much of this
// is identical to the equivalent host-side structure, but some additional
// information is needed so the structure and associated routines are not
// shared.
typedef struct UsbTest {

    // A unique identifier to make verbose output easier to understand
    int                 id;
    
    // Which test should be run
    usbtest             which_test;

    // Test-specific details.
    union {
        UsbTest_Bulk        bulk;
        UsbTest_ControlIn   control_in;
    } test_params;

    // How to recover from any problems. Specifically, what kind of message
    // could the target send or receive that would unlock the thread on this
    // side.
    UsbTest_Recovery    recovery;

    // The test result, to be collected and passed back to the host.
    int                 result_pass;
    char                result_message[USBTEST_MAX_MESSAGE];

    // Support for synchronization. This allows the UsbTest structure to be
    // used as the callback data for low-level USB calls.
    cyg_sem_t           sem;
    int                 transferred;

    // Some tests may need extra cancellation support
    void                (*cancel_fn)(struct UsbTest*);
    unsigned char       buffer[USBTEST_MAX_BULK_DATA + USBTEST_MAX_BULK_DATA_EXTRA];
} UsbTest;

// Reset the information in a given test. This is used by the pool allocation
// code. The data union is left alone, filling in the appropriate union
// member is left to other code.
static void
reset_usbtest(UsbTest* test)
{
    static int next_id = 1;
    test->id                    = next_id++;
    test->which_test            = usbtest_invalid;
    usbtest_recovery_reset(&(test->recovery));
    test->result_pass           = 0;
    test->result_message[0]     = '\0';
    cyg_semaphore_init(&(test->sem), 0);
    test->transferred           = 0;
    test->cancel_fn             = (void (*)(UsbTest*)) 0;
}

// Forward declaration. The pool code depends on run_test(), setting up a test requires the pool.
static UsbTest* pool_allocate(void);

/*}}}*/
/*{{{  Bulk transfers                                           */

/*{{{  handle_test_bulk()                                       */

// Prepare for a bulk transfer test. This means allocating a thread to do
// the work, and extracting the test parameters from the current buffer.
// The thread allocation code does not require any locking since all worker
// threads should be idle when starting a new thread, so the work can be
// done entirely at DSR level and no synch is required.
static usbs_control_return
handle_test_bulk(usb_devreq* req)
{
    UsbTest*    test;
    int         index   = 0;

    test = pool_allocate();
    unpack_usbtest_bulk(&(test->test_params.bulk), class_request, &index);
    test->which_test = (USB_DEVREQ_DIRECTION_IN == (test->test_params.bulk.endpoint & USB_DEVREQ_DIRECTION_MASK)) ?
        usbtest_bulk_in : usbtest_bulk_out;

    VERBOSE(3, "Preparing USB bulk test on endpoint %d, direction %s, for %d packets\n", \
            test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK,                \
            (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);
    
    return USBS_CONTROL_RETURN_HANDLED;
}

/*}}}*/
/*{{{  run_test_bulk_out()                                      */

// The same callback can be used for IN and OUT transfers. Note that
// starting the next transfer is left to the thread, it is not done
// at DSR level.
static void
run_test_bulk_in_out_callback(void* callback_arg, int transferred)
{
    UsbTest*    test    = (UsbTest*) callback_arg;
    test->transferred   = transferred;
    cyg_semaphore_post(&(test->sem));
}

// OUT transfers, i.e. the host will be sending some number of
// packets. The I/O can happen in a number of different ways, e.g. via
// the low-level USB API or via devtab routines.
static void
run_test_bulk_out(UsbTest* test)
{
    unsigned char*      buf;
    int                 endpoint_number = test->test_params.bulk.endpoint & ~USB_DEVREQ_DIRECTION_MASK;
    int                 ep_index;
    usbs_rx_endpoint*   endpoint        = 0;
    cyg_io_handle_t     io_handle       = (cyg_io_handle_t)0;
    int                 alignment;
    int                 transferred;
    int                 i;

    VERBOSE(1, "Starting test %d, bulk out on endpoint %d\n", test->id, endpoint_number);

    ep_index = lookup_endpoint(endpoint_number, USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK);
    if (ep_index == -1) {
            test->result_pass   = 0;
            snprintf(test->result_message, USBTEST_MAX_MESSAGE,
                     "Target, bulk OUT transfer on endpoint %d: no such bulk endpoint", endpoint_number);
            return;
    }
    endpoint    = (usbs_rx_endpoint*) usbs_testing_endpoints[ep_index].endpoint;
    alignment   = usbs_testing_endpoints[ep_index].alignment;
    if (0 != alignment) {
        buf         = (unsigned char*) ((((cyg_uint32)test->buffer) + alignment - 1) & ~(alignment - 1));
    } else {
        buf = test->buffer;

⌨️ 快捷键说明

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